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