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