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