1 /*
2 * linux/drivers/video/vgacon.c -- Low level VGA based console driver
3 *
4 * Created 28 Sep 1997 by Geert Uytterhoeven
5 *
6 * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
7 *
8 * This file is based on the old console.c, vga.c and vesa_blank.c drivers.
9 *
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 * 1995 Jay Estabrook
12 *
13 * User definable mapping table and font loading by Eugene G. Crosser,
14 * <crosser@average.org>
15 *
16 * Improved loadable font/UTF-8 support by H. Peter Anvin
17 * Feb-Sep 1995 <peter.anvin@linux.org>
18 *
19 * Colour palette handling, by Simon Tatham
20 * 17-Jun-95 <sgt20@cam.ac.uk>
21 *
22 * if 512 char mode is already enabled don't re-enable it,
23 * because it causes screen to flicker, by Mitja Horvat
24 * 5-May-96 <mitja.horvat@guest.arnes.si>
25 *
26 * Use 2 outw instead of 4 outb_p to reduce erroneous text
27 * flashing on RHS of screen during heavy console scrolling .
28 * Oct 1996, Paul Gortmaker.
29 *
30 *
31 * This file is subject to the terms and conditions of the GNU General Public
32 * License. See the file COPYING in the main directory of this archive for
33 * more details.
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
54 static DEFINE_RAW_SPINLOCK(vga_lock);
55 static int cursor_size_lastfrom;
56 static int cursor_size_lastto;
57 static u32 vgacon_xres;
58 static u32 vgacon_yres;
59 static struct vgastate vgastate;
60
61 #define BLANK 0x0020
62
63 #define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */
64 /*
65 * Interface used by the world
66 */
67
68 static const char *vgacon_startup(void);
69 static void vgacon_init(struct vc_data *c, int init);
70 static void vgacon_deinit(struct vc_data *c);
71 static void vgacon_cursor(struct vc_data *c, int mode);
72 static int vgacon_switch(struct vc_data *c);
73 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
74 static void vgacon_scrolldelta(struct vc_data *c, int lines);
75 static int vgacon_set_origin(struct vc_data *c);
76 static void vgacon_save_screen(struct vc_data *c);
77 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
78 static struct uni_pagedir *vgacon_uni_pagedir;
79 static int vgacon_refcount;
80
81 /* Description of the hardware situation */
82 static bool vga_init_done;
83 static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
84 static unsigned long vga_vram_end __read_mostly; /* End of video memory */
85 static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
86 static u16 vga_video_port_reg __read_mostly; /* Video register select port */
87 static u16 vga_video_port_val __read_mostly; /* Video register value port */
88 static unsigned int vga_video_num_columns; /* Number of text columns */
89 static unsigned int vga_video_num_lines; /* Number of text lines */
90 static bool vga_can_do_color; /* Do we support colors? */
91 static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
92 static unsigned char vga_video_type __read_mostly; /* Card type */
93 static bool vga_font_is_default = true;
94 static int vga_vesa_blanked;
95 static bool vga_palette_blanked;
96 static bool vga_is_gfx;
97 static bool vga_512_chars;
98 static int vga_video_font_height;
99 static int vga_scan_lines __read_mostly;
100 static unsigned int vga_rolled_over;
101
102 static bool vgacon_text_mode_force;
103 static bool vga_hardscroll_enabled;
104 static bool vga_hardscroll_user_enable = true;
105
vgacon_text_force(void)106 bool vgacon_text_force(void)
107 {
108 return vgacon_text_mode_force;
109 }
110 EXPORT_SYMBOL(vgacon_text_force);
111
text_mode(char * str)112 static int __init text_mode(char *str)
113 {
114 vgacon_text_mode_force = true;
115
116 pr_warning("You have booted with nomodeset. This means your GPU drivers are DISABLED\n");
117 pr_warning("Any video related functionality will be severely degraded, and you may not even be able to suspend the system properly\n");
118 pr_warning("Unless you actually understand what nomodeset does, you should reboot without enabling it\n");
119
120 return 1;
121 }
122
123 /* force text mode - used by kernel modesetting */
124 __setup("nomodeset", text_mode);
125
no_scroll(char * str)126 static int __init no_scroll(char *str)
127 {
128 /*
129 * Disabling scrollback is required for the Braillex ib80-piezo
130 * Braille reader made by F.H. Papenmeier (Germany).
131 * Use the "no-scroll" bootflag.
132 */
133 vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
134 return 1;
135 }
136
137 __setup("no-scroll", no_scroll);
138
139 /*
140 * By replacing the four outb_p with two back to back outw, we can reduce
141 * the window of opportunity to see text mislocated to the RHS of the
142 * console during heavy scrolling activity. However there is the remote
143 * possibility that some pre-dinosaur hardware won't like the back to back
144 * I/O. Since the Xservers get away with it, we should be able to as well.
145 */
write_vga(unsigned char reg,unsigned int val)146 static inline void write_vga(unsigned char reg, unsigned int val)
147 {
148 unsigned int v1, v2;
149 unsigned long flags;
150
151 /*
152 * ddprintk might set the console position from interrupt
153 * handlers, thus the write has to be IRQ-atomic.
154 */
155 raw_spin_lock_irqsave(&vga_lock, flags);
156 v1 = reg + (val & 0xff00);
157 v2 = reg + 1 + ((val << 8) & 0xff00);
158 outw(v1, vga_video_port_reg);
159 outw(v2, vga_video_port_reg);
160 raw_spin_unlock_irqrestore(&vga_lock, flags);
161 }
162
vga_set_mem_top(struct vc_data * c)163 static inline void vga_set_mem_top(struct vc_data *c)
164 {
165 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
166 }
167
vgacon_restore_screen(struct vc_data * c)168 static void vgacon_restore_screen(struct vc_data *c)
169 {
170 if (c->vc_origin != c->vc_visible_origin)
171 vgacon_scrolldelta(c, 0);
172 }
173
vgacon_scrolldelta(struct vc_data * c,int lines)174 static void vgacon_scrolldelta(struct vc_data *c, int lines)
175 {
176 vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
177 vga_vram_size);
178 vga_set_mem_top(c);
179 }
180
vgacon_startup(void)181 static const char *vgacon_startup(void)
182 {
183 const char *display_desc = NULL;
184 u16 saved1, saved2;
185 volatile u16 *p;
186
187 if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
188 screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
189 no_vga:
190 #ifdef CONFIG_DUMMY_CONSOLE
191 conswitchp = &dummy_con;
192 return conswitchp->con_startup();
193 #else
194 return NULL;
195 #endif
196 }
197
198 /* boot_params.screen_info reasonably initialized? */
199 if ((screen_info.orig_video_lines == 0) ||
200 (screen_info.orig_video_cols == 0))
201 goto no_vga;
202
203 /* VGA16 modes are not handled by VGACON */
204 if ((screen_info.orig_video_mode == 0x0D) || /* 320x200/4 */
205 (screen_info.orig_video_mode == 0x0E) || /* 640x200/4 */
206 (screen_info.orig_video_mode == 0x10) || /* 640x350/4 */
207 (screen_info.orig_video_mode == 0x12) || /* 640x480/4 */
208 (screen_info.orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */
209 goto no_vga;
210
211 vga_video_num_lines = screen_info.orig_video_lines;
212 vga_video_num_columns = screen_info.orig_video_cols;
213 vgastate.vgabase = NULL;
214
215 if (screen_info.orig_video_mode == 7) {
216 /* Monochrome display */
217 vga_vram_base = 0xb0000;
218 vga_video_port_reg = VGA_CRT_IM;
219 vga_video_port_val = VGA_CRT_DM;
220 if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
221 static struct resource ega_console_resource =
222 { .name = "ega",
223 .flags = IORESOURCE_IO,
224 .start = 0x3B0,
225 .end = 0x3BF };
226 vga_video_type = VIDEO_TYPE_EGAM;
227 vga_vram_size = 0x8000;
228 display_desc = "EGA+";
229 request_resource(&ioport_resource,
230 &ega_console_resource);
231 } else {
232 static struct resource mda1_console_resource =
233 { .name = "mda",
234 .flags = IORESOURCE_IO,
235 .start = 0x3B0,
236 .end = 0x3BB };
237 static struct resource mda2_console_resource =
238 { .name = "mda",
239 .flags = IORESOURCE_IO,
240 .start = 0x3BF,
241 .end = 0x3BF };
242 vga_video_type = VIDEO_TYPE_MDA;
243 vga_vram_size = 0x2000;
244 display_desc = "*MDA";
245 request_resource(&ioport_resource,
246 &mda1_console_resource);
247 request_resource(&ioport_resource,
248 &mda2_console_resource);
249 vga_video_font_height = 14;
250 }
251 } else {
252 /* If not, it is color. */
253 vga_can_do_color = true;
254 vga_vram_base = 0xb8000;
255 vga_video_port_reg = VGA_CRT_IC;
256 vga_video_port_val = VGA_CRT_DC;
257 if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
258 int i;
259
260 vga_vram_size = 0x8000;
261
262 if (!screen_info.orig_video_isVGA) {
263 static struct resource ega_console_resource =
264 { .name = "ega",
265 .flags = IORESOURCE_IO,
266 .start = 0x3C0,
267 .end = 0x3DF };
268 vga_video_type = VIDEO_TYPE_EGAC;
269 display_desc = "EGA";
270 request_resource(&ioport_resource,
271 &ega_console_resource);
272 } else {
273 static struct resource vga_console_resource =
274 { .name = "vga+",
275 .flags = IORESOURCE_IO,
276 .start = 0x3C0,
277 .end = 0x3DF };
278 vga_video_type = VIDEO_TYPE_VGAC;
279 display_desc = "VGA+";
280 request_resource(&ioport_resource,
281 &vga_console_resource);
282
283 /*
284 * Normalise the palette registers, to point
285 * the 16 screen colours to the first 16
286 * DAC entries.
287 */
288
289 for (i = 0; i < 16; i++) {
290 inb_p(VGA_IS1_RC);
291 outb_p(i, VGA_ATT_W);
292 outb_p(i, VGA_ATT_W);
293 }
294 outb_p(0x20, VGA_ATT_W);
295
296 /*
297 * Now set the DAC registers back to their
298 * default values
299 */
300 for (i = 0; i < 16; i++) {
301 outb_p(color_table[i], VGA_PEL_IW);
302 outb_p(default_red[i], VGA_PEL_D);
303 outb_p(default_grn[i], VGA_PEL_D);
304 outb_p(default_blu[i], VGA_PEL_D);
305 }
306 }
307 } else {
308 static struct resource cga_console_resource =
309 { .name = "cga",
310 .flags = IORESOURCE_IO,
311 .start = 0x3D4,
312 .end = 0x3D5 };
313 vga_video_type = VIDEO_TYPE_CGA;
314 vga_vram_size = 0x2000;
315 display_desc = "*CGA";
316 request_resource(&ioport_resource,
317 &cga_console_resource);
318 vga_video_font_height = 8;
319 }
320 }
321
322 vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
323 vga_vram_end = vga_vram_base + vga_vram_size;
324
325 /*
326 * Find out if there is a graphics card present.
327 * Are there smarter methods around?
328 */
329 p = (volatile u16 *) vga_vram_base;
330 saved1 = scr_readw(p);
331 saved2 = scr_readw(p + 1);
332 scr_writew(0xAA55, p);
333 scr_writew(0x55AA, p + 1);
334 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
335 scr_writew(saved1, p);
336 scr_writew(saved2, p + 1);
337 goto no_vga;
338 }
339 scr_writew(0x55AA, p);
340 scr_writew(0xAA55, p + 1);
341 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
342 scr_writew(saved1, p);
343 scr_writew(saved2, p + 1);
344 goto no_vga;
345 }
346 scr_writew(saved1, p);
347 scr_writew(saved2, p + 1);
348
349 if (vga_video_type == VIDEO_TYPE_EGAC
350 || vga_video_type == VIDEO_TYPE_VGAC
351 || vga_video_type == VIDEO_TYPE_EGAM) {
352 vga_hardscroll_enabled = vga_hardscroll_user_enable;
353 vga_default_font_height = screen_info.orig_video_points;
354 vga_video_font_height = screen_info.orig_video_points;
355 /* This may be suboptimal but is a safe bet - go with it */
356 vga_scan_lines =
357 vga_video_font_height * vga_video_num_lines;
358 }
359
360 vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
361 vgacon_yres = vga_scan_lines;
362
363 vga_init_done = true;
364
365 return display_desc;
366 }
367
vgacon_init(struct vc_data * c,int init)368 static void vgacon_init(struct vc_data *c, int init)
369 {
370 struct uni_pagedir *p;
371
372 /*
373 * We cannot be loaded as a module, therefore init is always 1,
374 * but vgacon_init can be called more than once, and init will
375 * not be 1.
376 */
377 c->vc_can_do_color = vga_can_do_color;
378
379 /* set dimensions manually if init != 0 since vc_resize() will fail */
380 if (init) {
381 c->vc_cols = vga_video_num_columns;
382 c->vc_rows = vga_video_num_lines;
383 } else
384 vc_resize(c, vga_video_num_columns, vga_video_num_lines);
385
386 c->vc_scan_lines = vga_scan_lines;
387 c->vc_font.height = vga_video_font_height;
388 c->vc_complement_mask = 0x7700;
389 if (vga_512_chars)
390 c->vc_hi_font_mask = 0x0800;
391 p = *c->vc_uni_pagedir_loc;
392 if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
393 con_free_unimap(c);
394 c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
395 vgacon_refcount++;
396 }
397 if (!vgacon_uni_pagedir && p)
398 con_set_default_unimap(c);
399
400 /* Only set the default if the user didn't deliberately override it */
401 if (global_cursor_default == -1)
402 global_cursor_default =
403 !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
404 }
405
vgacon_deinit(struct vc_data * c)406 static void vgacon_deinit(struct vc_data *c)
407 {
408 /* When closing the active console, reset video origin */
409 if (con_is_visible(c)) {
410 c->vc_visible_origin = vga_vram_base;
411 vga_set_mem_top(c);
412 }
413
414 if (!--vgacon_refcount)
415 con_free_unimap(c);
416 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
417 con_set_default_unimap(c);
418 }
419
vgacon_build_attr(struct vc_data * c,u8 color,u8 intensity,u8 blink,u8 underline,u8 reverse,u8 italic)420 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
421 u8 blink, u8 underline, u8 reverse, u8 italic)
422 {
423 u8 attr = color;
424
425 if (vga_can_do_color) {
426 if (italic)
427 attr = (attr & 0xF0) | c->vc_itcolor;
428 else if (underline)
429 attr = (attr & 0xf0) | c->vc_ulcolor;
430 else if (intensity == 0)
431 attr = (attr & 0xf0) | c->vc_halfcolor;
432 }
433 if (reverse)
434 attr =
435 ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
436 0x77);
437 if (blink)
438 attr ^= 0x80;
439 if (intensity == 2)
440 attr ^= 0x08;
441 if (!vga_can_do_color) {
442 if (italic)
443 attr = (attr & 0xF8) | 0x02;
444 else if (underline)
445 attr = (attr & 0xf8) | 0x01;
446 else if (intensity == 0)
447 attr = (attr & 0xf0) | 0x08;
448 }
449 return attr;
450 }
451
vgacon_invert_region(struct vc_data * c,u16 * p,int count)452 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
453 {
454 const bool col = vga_can_do_color;
455
456 while (count--) {
457 u16 a = scr_readw(p);
458 if (col)
459 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
460 (((a) & 0x0700) << 4);
461 else
462 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
463 scr_writew(a, p++);
464 }
465 }
466
vgacon_set_cursor_size(int xpos,int from,int to)467 static void vgacon_set_cursor_size(int xpos, int from, int to)
468 {
469 unsigned long flags;
470 int curs, cure;
471
472 if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
473 return;
474 cursor_size_lastfrom = from;
475 cursor_size_lastto = to;
476
477 raw_spin_lock_irqsave(&vga_lock, flags);
478 if (vga_video_type >= VIDEO_TYPE_VGAC) {
479 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
480 curs = inb_p(vga_video_port_val);
481 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
482 cure = inb_p(vga_video_port_val);
483 } else {
484 curs = 0;
485 cure = 0;
486 }
487
488 curs = (curs & 0xc0) | from;
489 cure = (cure & 0xe0) | to;
490
491 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
492 outb_p(curs, vga_video_port_val);
493 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
494 outb_p(cure, vga_video_port_val);
495 raw_spin_unlock_irqrestore(&vga_lock, flags);
496 }
497
vgacon_cursor(struct vc_data * c,int mode)498 static void vgacon_cursor(struct vc_data *c, int mode)
499 {
500 if (c->vc_mode != KD_TEXT)
501 return;
502
503 vgacon_restore_screen(c);
504
505 switch (mode) {
506 case CM_ERASE:
507 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
508 if (vga_video_type >= VIDEO_TYPE_VGAC)
509 vgacon_set_cursor_size(c->vc_x, 31, 30);
510 else
511 vgacon_set_cursor_size(c->vc_x, 31, 31);
512 break;
513
514 case CM_MOVE:
515 case CM_DRAW:
516 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
517 switch (c->vc_cursor_type & 0x0f) {
518 case CUR_UNDERLINE:
519 vgacon_set_cursor_size(c->vc_x,
520 c->vc_font.height -
521 (c->vc_font.height <
522 10 ? 2 : 3),
523 c->vc_font.height -
524 (c->vc_font.height <
525 10 ? 1 : 2));
526 break;
527 case CUR_TWO_THIRDS:
528 vgacon_set_cursor_size(c->vc_x,
529 c->vc_font.height / 3,
530 c->vc_font.height -
531 (c->vc_font.height <
532 10 ? 1 : 2));
533 break;
534 case CUR_LOWER_THIRD:
535 vgacon_set_cursor_size(c->vc_x,
536 (c->vc_font.height * 2) / 3,
537 c->vc_font.height -
538 (c->vc_font.height <
539 10 ? 1 : 2));
540 break;
541 case CUR_LOWER_HALF:
542 vgacon_set_cursor_size(c->vc_x,
543 c->vc_font.height / 2,
544 c->vc_font.height -
545 (c->vc_font.height <
546 10 ? 1 : 2));
547 break;
548 case CUR_NONE:
549 if (vga_video_type >= VIDEO_TYPE_VGAC)
550 vgacon_set_cursor_size(c->vc_x, 31, 30);
551 else
552 vgacon_set_cursor_size(c->vc_x, 31, 31);
553 break;
554 default:
555 vgacon_set_cursor_size(c->vc_x, 1,
556 c->vc_font.height);
557 break;
558 }
559 break;
560 }
561 }
562
vgacon_doresize(struct vc_data * c,unsigned int width,unsigned int height)563 static int vgacon_doresize(struct vc_data *c,
564 unsigned int width, unsigned int height)
565 {
566 unsigned long flags;
567 unsigned int scanlines = height * c->vc_font.height;
568 u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
569
570 raw_spin_lock_irqsave(&vga_lock, flags);
571
572 vgacon_xres = width * VGA_FONTWIDTH;
573 vgacon_yres = height * c->vc_font.height;
574 if (vga_video_type >= VIDEO_TYPE_VGAC) {
575 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
576 max_scan = inb_p(vga_video_port_val);
577
578 if (max_scan & 0x80)
579 scanlines <<= 1;
580
581 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
582 mode = inb_p(vga_video_port_val);
583
584 if (mode & 0x04)
585 scanlines >>= 1;
586
587 scanlines -= 1;
588 scanlines_lo = scanlines & 0xff;
589
590 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
591 r7 = inb_p(vga_video_port_val) & ~0x42;
592
593 if (scanlines & 0x100)
594 r7 |= 0x02;
595 if (scanlines & 0x200)
596 r7 |= 0x40;
597
598 /* deprotect registers */
599 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
600 vsync_end = inb_p(vga_video_port_val);
601 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
602 outb_p(vsync_end & ~0x80, vga_video_port_val);
603 }
604
605 outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
606 outb_p(width - 1, vga_video_port_val);
607 outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
608 outb_p(width >> 1, vga_video_port_val);
609
610 if (vga_video_type >= VIDEO_TYPE_VGAC) {
611 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
612 outb_p(scanlines_lo, vga_video_port_val);
613 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
614 outb_p(r7,vga_video_port_val);
615
616 /* reprotect registers */
617 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
618 outb_p(vsync_end, vga_video_port_val);
619 }
620
621 raw_spin_unlock_irqrestore(&vga_lock, flags);
622 return 0;
623 }
624
vgacon_switch(struct vc_data * c)625 static int vgacon_switch(struct vc_data *c)
626 {
627 int x = c->vc_cols * VGA_FONTWIDTH;
628 int y = c->vc_rows * c->vc_font.height;
629 int rows = screen_info.orig_video_lines * vga_default_font_height/
630 c->vc_font.height;
631 /*
632 * We need to save screen size here as it's the only way
633 * we can spot the screen has been resized and we need to
634 * set size of freshly allocated screens ourselves.
635 */
636 vga_video_num_columns = c->vc_cols;
637 vga_video_num_lines = c->vc_rows;
638
639 /* We can only copy out the size of the video buffer here,
640 * otherwise we get into VGA BIOS */
641
642 if (!vga_is_gfx) {
643 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
644 c->vc_screenbuf_size > vga_vram_size ?
645 vga_vram_size : c->vc_screenbuf_size);
646
647 if ((vgacon_xres != x || vgacon_yres != y) &&
648 (!(vga_video_num_columns % 2) &&
649 vga_video_num_columns <= screen_info.orig_video_cols &&
650 vga_video_num_lines <= rows))
651 vgacon_doresize(c, c->vc_cols, c->vc_rows);
652 }
653
654 return 0; /* Redrawing not needed */
655 }
656
vga_set_palette(struct vc_data * vc,const unsigned char * table)657 static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
658 {
659 int i, j;
660
661 vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
662 for (i = j = 0; i < 16; i++) {
663 vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
664 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
665 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
666 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
667 }
668 }
669
vgacon_set_palette(struct vc_data * vc,const unsigned char * table)670 static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
671 {
672 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
673 || !con_is_visible(vc))
674 return;
675 vga_set_palette(vc, table);
676 }
677
678 /* structure holding original VGA register settings */
679 static struct {
680 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
681 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
682 unsigned char CrtMiscIO; /* Miscellaneous register */
683 unsigned char HorizontalTotal; /* CRT-Controller:00h */
684 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
685 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
686 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
687 unsigned char Overflow; /* CRT-Controller:07h */
688 unsigned char StartVertRetrace; /* CRT-Controller:10h */
689 unsigned char EndVertRetrace; /* CRT-Controller:11h */
690 unsigned char ModeControl; /* CRT-Controller:17h */
691 unsigned char ClockingMode; /* Seq-Controller:01h */
692 } vga_state;
693
vga_vesa_blank(struct vgastate * state,int mode)694 static void vga_vesa_blank(struct vgastate *state, int mode)
695 {
696 /* save original values of VGA controller registers */
697 if (!vga_vesa_blanked) {
698 raw_spin_lock_irq(&vga_lock);
699 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
700 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
701 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
702 raw_spin_unlock_irq(&vga_lock);
703
704 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
705 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
706 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
707 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
708 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
709 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
710 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
711 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
712 outb_p(0x07, vga_video_port_reg); /* Overflow */
713 vga_state.Overflow = inb_p(vga_video_port_val);
714 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
715 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
716 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
717 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
718 outb_p(0x17, vga_video_port_reg); /* ModeControl */
719 vga_state.ModeControl = inb_p(vga_video_port_val);
720 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
721 }
722
723 /* assure that video is enabled */
724 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
725 raw_spin_lock_irq(&vga_lock);
726 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
727
728 /* test for vertical retrace in process.... */
729 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
730 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
731
732 /*
733 * Set <End of vertical retrace> to minimum (0) and
734 * <Start of vertical Retrace> to maximum (incl. overflow)
735 * Result: turn off vertical sync (VSync) pulse.
736 */
737 if (mode & VESA_VSYNC_SUSPEND) {
738 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
739 outb_p(0xff, vga_video_port_val); /* maximum value */
740 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
741 outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */
742 outb_p(0x07, vga_video_port_reg); /* Overflow */
743 outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */
744 }
745
746 if (mode & VESA_HSYNC_SUSPEND) {
747 /*
748 * Set <End of horizontal retrace> to minimum (0) and
749 * <Start of horizontal Retrace> to maximum
750 * Result: turn off horizontal sync (HSync) pulse.
751 */
752 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
753 outb_p(0xff, vga_video_port_val); /* maximum */
754 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
755 outb_p(0x00, vga_video_port_val); /* minimum (0) */
756 }
757
758 /* restore both index registers */
759 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
760 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
761 raw_spin_unlock_irq(&vga_lock);
762 }
763
vga_vesa_unblank(struct vgastate * state)764 static void vga_vesa_unblank(struct vgastate *state)
765 {
766 /* restore original values of VGA controller registers */
767 raw_spin_lock_irq(&vga_lock);
768 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
769
770 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
771 outb_p(vga_state.HorizontalTotal, vga_video_port_val);
772 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
773 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
774 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
775 outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
776 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
777 outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
778 outb_p(0x07, vga_video_port_reg); /* Overflow */
779 outb_p(vga_state.Overflow, vga_video_port_val);
780 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
781 outb_p(vga_state.StartVertRetrace, vga_video_port_val);
782 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
783 outb_p(vga_state.EndVertRetrace, vga_video_port_val);
784 outb_p(0x17, vga_video_port_reg); /* ModeControl */
785 outb_p(vga_state.ModeControl, vga_video_port_val);
786 /* ClockingMode */
787 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
788
789 /* restore index/control registers */
790 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
791 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
792 raw_spin_unlock_irq(&vga_lock);
793 }
794
vga_pal_blank(struct vgastate * state)795 static void vga_pal_blank(struct vgastate *state)
796 {
797 int i;
798
799 vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
800 for (i = 0; i < 16; i++) {
801 vga_w(state->vgabase, VGA_PEL_IW, i);
802 vga_w(state->vgabase, VGA_PEL_D, 0);
803 vga_w(state->vgabase, VGA_PEL_D, 0);
804 vga_w(state->vgabase, VGA_PEL_D, 0);
805 }
806 }
807
vgacon_blank(struct vc_data * c,int blank,int mode_switch)808 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
809 {
810 switch (blank) {
811 case 0: /* Unblank */
812 if (vga_vesa_blanked) {
813 vga_vesa_unblank(&vgastate);
814 vga_vesa_blanked = 0;
815 }
816 if (vga_palette_blanked) {
817 vga_set_palette(c, color_table);
818 vga_palette_blanked = false;
819 return 0;
820 }
821 vga_is_gfx = false;
822 /* Tell console.c that it has to restore the screen itself */
823 return 1;
824 case 1: /* Normal blanking */
825 case -1: /* Obsolete */
826 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
827 vga_pal_blank(&vgastate);
828 vga_palette_blanked = true;
829 return 0;
830 }
831 vgacon_set_origin(c);
832 scr_memsetw((void *) vga_vram_base, BLANK,
833 c->vc_screenbuf_size);
834 if (mode_switch)
835 vga_is_gfx = true;
836 return 1;
837 default: /* VESA blanking */
838 if (vga_video_type == VIDEO_TYPE_VGAC) {
839 vga_vesa_blank(&vgastate, blank - 1);
840 vga_vesa_blanked = blank;
841 }
842 return 0;
843 }
844 }
845
846 /*
847 * PIO_FONT support.
848 *
849 * The font loading code goes back to the codepage package by
850 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
851 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
852 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
853 *
854 * Change for certain monochrome monitors by Yury Shevchuck
855 * (sizif@botik.yaroslavl.su).
856 */
857
858 #define colourmap 0xa0000
859 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
860 should use 0xA0000 for the bwmap as well.. */
861 #define blackwmap 0xa0000
862 #define cmapsz 8192
863
vgacon_do_font_op(struct vgastate * state,char * arg,int set,bool ch512)864 static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
865 bool ch512)
866 {
867 unsigned short video_port_status = vga_video_port_reg + 6;
868 int font_select = 0x00, beg, i;
869 char *charmap;
870 bool clear_attribs = false;
871 if (vga_video_type != VIDEO_TYPE_EGAM) {
872 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
873 beg = 0x0e;
874 } else {
875 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
876 beg = 0x0a;
877 }
878
879 #ifdef BROKEN_GRAPHICS_PROGRAMS
880 /*
881 * All fonts are loaded in slot 0 (0:1 for 512 ch)
882 */
883
884 if (!arg)
885 return -EINVAL; /* Return to default font not supported */
886
887 vga_font_is_default = false;
888 font_select = ch512 ? 0x04 : 0x00;
889 #else
890 /*
891 * The default font is kept in slot 0 and is never touched.
892 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
893 */
894
895 if (set) {
896 vga_font_is_default = !arg;
897 if (!arg)
898 ch512 = false; /* Default font is always 256 */
899 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
900 }
901
902 if (!vga_font_is_default)
903 charmap += 4 * cmapsz;
904 #endif
905
906 raw_spin_lock_irq(&vga_lock);
907 /* First, the Sequencer */
908 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
909 /* CPU writes only to map 2 */
910 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
911 /* Sequential addressing */
912 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
913 /* Clear synchronous reset */
914 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
915
916 /* Now, the graphics controller, select map 2 */
917 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
918 /* disable odd-even addressing */
919 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
920 /* map start at A000:0000 */
921 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
922 raw_spin_unlock_irq(&vga_lock);
923
924 if (arg) {
925 if (set)
926 for (i = 0; i < cmapsz; i++) {
927 vga_writeb(arg[i], charmap + i);
928 cond_resched();
929 }
930 else
931 for (i = 0; i < cmapsz; i++) {
932 arg[i] = vga_readb(charmap + i);
933 cond_resched();
934 }
935
936 /*
937 * In 512-character mode, the character map is not contiguous if
938 * we want to remain EGA compatible -- which we do
939 */
940
941 if (ch512) {
942 charmap += 2 * cmapsz;
943 arg += cmapsz;
944 if (set)
945 for (i = 0; i < cmapsz; i++) {
946 vga_writeb(arg[i], charmap + i);
947 cond_resched();
948 }
949 else
950 for (i = 0; i < cmapsz; i++) {
951 arg[i] = vga_readb(charmap + i);
952 cond_resched();
953 }
954 }
955 }
956
957 raw_spin_lock_irq(&vga_lock);
958 /* First, the sequencer, Synchronous reset */
959 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
960 /* CPU writes to maps 0 and 1 */
961 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
962 /* odd-even addressing */
963 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
964 /* Character Map Select */
965 if (set)
966 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
967 /* clear synchronous reset */
968 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
969
970 /* Now, the graphics controller, select map 0 for CPU */
971 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
972 /* enable even-odd addressing */
973 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
974 /* map starts at b800:0 or b000:0 */
975 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
976
977 /* if 512 char mode is already enabled don't re-enable it. */
978 if ((set) && (ch512 != vga_512_chars)) {
979 vga_512_chars = ch512;
980 /* 256-char: enable intensity bit
981 512-char: disable intensity bit */
982 inb_p(video_port_status); /* clear address flip-flop */
983 /* color plane enable register */
984 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
985 /* Wilton (1987) mentions the following; I don't know what
986 it means, but it works, and it appears necessary */
987 inb_p(video_port_status);
988 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
989 clear_attribs = true;
990 }
991 raw_spin_unlock_irq(&vga_lock);
992
993 if (clear_attribs) {
994 for (i = 0; i < MAX_NR_CONSOLES; i++) {
995 struct vc_data *c = vc_cons[i].d;
996 if (c && c->vc_sw == &vga_con) {
997 /* force hi font mask to 0, so we always clear
998 the bit on either transition */
999 c->vc_hi_font_mask = 0x00;
1000 clear_buffer_attributes(c);
1001 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1002 }
1003 }
1004 }
1005 return 0;
1006 }
1007
1008 /*
1009 * Adjust the screen to fit a font of a certain height
1010 */
vgacon_adjust_height(struct vc_data * vc,unsigned fontheight)1011 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1012 {
1013 unsigned char ovr, vde, fsr;
1014 int rows, maxscan, i;
1015
1016 rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */
1017 maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */
1018
1019 /* Reprogram the CRTC for the new font size
1020 Note: the attempt to read the overflow register will fail
1021 on an EGA, but using 0xff for the previous value appears to
1022 be OK for EGA text modes in the range 257-512 scan lines, so I
1023 guess we don't need to worry about it.
1024
1025 The same applies for the spill bits in the font size and cursor
1026 registers; they are write-only on EGA, but it appears that they
1027 are all don't care bits on EGA, so I guess it doesn't matter. */
1028
1029 raw_spin_lock_irq(&vga_lock);
1030 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
1031 ovr = inb_p(vga_video_port_val);
1032 outb_p(0x09, vga_video_port_reg); /* Font size register */
1033 fsr = inb_p(vga_video_port_val);
1034 raw_spin_unlock_irq(&vga_lock);
1035
1036 vde = maxscan & 0xff; /* Vertical display end reg */
1037 ovr = (ovr & 0xbd) + /* Overflow register */
1038 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1039 fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */
1040
1041 raw_spin_lock_irq(&vga_lock);
1042 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
1043 outb_p(ovr, vga_video_port_val);
1044 outb_p(0x09, vga_video_port_reg); /* Font size */
1045 outb_p(fsr, vga_video_port_val);
1046 outb_p(0x12, vga_video_port_reg); /* Vertical display limit */
1047 outb_p(vde, vga_video_port_val);
1048 raw_spin_unlock_irq(&vga_lock);
1049 vga_video_font_height = fontheight;
1050
1051 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1052 struct vc_data *c = vc_cons[i].d;
1053
1054 if (c && c->vc_sw == &vga_con) {
1055 if (con_is_visible(c)) {
1056 /* void size to cause regs to be rewritten */
1057 cursor_size_lastfrom = 0;
1058 cursor_size_lastto = 0;
1059 c->vc_sw->con_cursor(c, CM_DRAW);
1060 }
1061 c->vc_font.height = fontheight;
1062 vc_resize(c, 0, rows); /* Adjust console size */
1063 }
1064 }
1065 return 0;
1066 }
1067
vgacon_font_set(struct vc_data * c,struct console_font * font,unsigned int flags)1068 static int vgacon_font_set(struct vc_data *c, struct console_font *font,
1069 unsigned int flags)
1070 {
1071 unsigned charcount = font->charcount;
1072 int rc;
1073
1074 if (vga_video_type < VIDEO_TYPE_EGAM)
1075 return -EINVAL;
1076
1077 if (font->width != VGA_FONTWIDTH ||
1078 (charcount != 256 && charcount != 512))
1079 return -EINVAL;
1080
1081 rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
1082 if (rc)
1083 return rc;
1084
1085 if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1086 rc = vgacon_adjust_height(c, font->height);
1087 return rc;
1088 }
1089
vgacon_font_get(struct vc_data * c,struct console_font * font)1090 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1091 {
1092 if (vga_video_type < VIDEO_TYPE_EGAM)
1093 return -EINVAL;
1094
1095 font->width = VGA_FONTWIDTH;
1096 font->height = c->vc_font.height;
1097 font->charcount = vga_512_chars ? 512 : 256;
1098 if (!font->data)
1099 return 0;
1100 return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
1101 }
1102
vgacon_resize(struct vc_data * c,unsigned int width,unsigned int height,unsigned int user)1103 static int vgacon_resize(struct vc_data *c, unsigned int width,
1104 unsigned int height, unsigned int user)
1105 {
1106 if ((width << 1) * height > vga_vram_size)
1107 return -EINVAL;
1108
1109 if (width % 2 || width > screen_info.orig_video_cols ||
1110 height > (screen_info.orig_video_lines * vga_default_font_height)/
1111 c->vc_font.height)
1112 /* let svgatextmode tinker with video timings and
1113 return success */
1114 return (user) ? 0 : -EINVAL;
1115
1116 if (con_is_visible(c) && !vga_is_gfx) /* who knows */
1117 vgacon_doresize(c, width, height);
1118 return 0;
1119 }
1120
vgacon_set_origin(struct vc_data * c)1121 static int vgacon_set_origin(struct vc_data *c)
1122 {
1123 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
1124 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
1125 return 0;
1126 c->vc_origin = c->vc_visible_origin = vga_vram_base;
1127 vga_set_mem_top(c);
1128 vga_rolled_over = 0;
1129 return 1;
1130 }
1131
vgacon_save_screen(struct vc_data * c)1132 static void vgacon_save_screen(struct vc_data *c)
1133 {
1134 static int vga_bootup_console = 0;
1135
1136 if (!vga_bootup_console) {
1137 /* This is a gross hack, but here is the only place we can
1138 * set bootup console parameters without messing up generic
1139 * console initialization routines.
1140 */
1141 vga_bootup_console = 1;
1142 c->vc_x = screen_info.orig_x;
1143 c->vc_y = screen_info.orig_y;
1144 }
1145
1146 /* We can't copy in more than the size of the video buffer,
1147 * or we'll be copying in VGA BIOS */
1148
1149 if (!vga_is_gfx)
1150 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1151 c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1152 }
1153
vgacon_scroll(struct vc_data * c,unsigned int t,unsigned int b,enum con_scroll dir,unsigned int lines)1154 static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
1155 enum con_scroll dir, unsigned int lines)
1156 {
1157 unsigned long oldo;
1158 unsigned int delta;
1159
1160 if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1161 return false;
1162
1163 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1164 return false;
1165
1166 vgacon_restore_screen(c);
1167 oldo = c->vc_origin;
1168 delta = lines * c->vc_size_row;
1169 if (dir == SM_UP) {
1170 if (c->vc_scr_end + delta >= vga_vram_end) {
1171 scr_memcpyw((u16 *) vga_vram_base,
1172 (u16 *) (oldo + delta),
1173 c->vc_screenbuf_size - delta);
1174 c->vc_origin = vga_vram_base;
1175 vga_rolled_over = oldo - vga_vram_base;
1176 } else
1177 c->vc_origin += delta;
1178 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1179 delta), c->vc_video_erase_char,
1180 delta);
1181 } else {
1182 if (oldo - delta < vga_vram_base) {
1183 scr_memmovew((u16 *) (vga_vram_end -
1184 c->vc_screenbuf_size +
1185 delta), (u16 *) oldo,
1186 c->vc_screenbuf_size - delta);
1187 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1188 vga_rolled_over = 0;
1189 } else
1190 c->vc_origin -= delta;
1191 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1192 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1193 delta);
1194 }
1195 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1196 c->vc_visible_origin = c->vc_origin;
1197 vga_set_mem_top(c);
1198 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1199 return true;
1200 }
1201
1202 /*
1203 * The console `switch' structure for the VGA based console
1204 */
1205
vgacon_clear(struct vc_data * vc,int sy,int sx,int height,int width)1206 static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
1207 int width) { }
vgacon_putc(struct vc_data * vc,int c,int ypos,int xpos)1208 static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
vgacon_putcs(struct vc_data * vc,const unsigned short * s,int count,int ypos,int xpos)1209 static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
1210 int count, int ypos, int xpos) { }
1211
1212 const struct consw vga_con = {
1213 .owner = THIS_MODULE,
1214 .con_startup = vgacon_startup,
1215 .con_init = vgacon_init,
1216 .con_deinit = vgacon_deinit,
1217 .con_clear = vgacon_clear,
1218 .con_putc = vgacon_putc,
1219 .con_putcs = vgacon_putcs,
1220 .con_cursor = vgacon_cursor,
1221 .con_scroll = vgacon_scroll,
1222 .con_switch = vgacon_switch,
1223 .con_blank = vgacon_blank,
1224 .con_font_set = vgacon_font_set,
1225 .con_font_get = vgacon_font_get,
1226 .con_resize = vgacon_resize,
1227 .con_set_palette = vgacon_set_palette,
1228 .con_scrolldelta = vgacon_scrolldelta,
1229 .con_set_origin = vgacon_set_origin,
1230 .con_save_screen = vgacon_save_screen,
1231 .con_build_attr = vgacon_build_attr,
1232 .con_invert_region = vgacon_invert_region,
1233 };
1234 EXPORT_SYMBOL(vga_con);
1235
1236 MODULE_LICENSE("GPL");
1237