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/config.h>
37 #include <linux/module.h>
38 #include <linux/types.h>
39 #include <linux/sched.h>
40 #include <linux/fs.h>
41 #include <linux/kernel.h>
42 #include <linux/tty.h>
43 #include <linux/console.h>
44 #include <linux/console_struct.h>
45 #include <linux/string.h>
46 #include <linux/kd.h>
47 #include <linux/slab.h>
48 #include <linux/vt_kern.h>
49 #include <linux/selection.h>
50 #include <linux/spinlock.h>
51 #include <linux/ioport.h>
52 #include <linux/init.h>
53
54 #include <asm/io.h>
55
56 static spinlock_t vga_lock = SPIN_LOCK_UNLOCKED;
57
58 #define BLANK 0x0020
59
60 #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
61 #define CAN_LOAD_PALETTE /* undefine if the user must not do this */
62
63 /* You really do _NOT_ want to define this, unless you have buggy
64 * Trident VGA which will resize cursor when moving it between column
65 * 15 & 16. If you define this and your VGA is OK, inverse bug will
66 * appear.
67 */
68 #undef TRIDENT_GLITCH
69
70 #define dac_reg 0x3c8
71 #define dac_val 0x3c9
72 #define attrib_port 0x3c0
73 #define seq_port_reg 0x3c4
74 #define seq_port_val 0x3c5
75 #define gr_port_reg 0x3ce
76 #define gr_port_val 0x3cf
77 #define video_misc_rd 0x3cc
78 #define video_misc_wr 0x3c2
79
80 /*
81 * Interface used by the world
82 */
83
84 static const char *vgacon_startup(void);
85 static void vgacon_init(struct vc_data *c, int init);
86 static void vgacon_deinit(struct vc_data *c);
87 static void vgacon_cursor(struct vc_data *c, int mode);
88 static int vgacon_switch(struct vc_data *c);
89 static int vgacon_blank(struct vc_data *c, int blank);
90 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op);
91 static int vgacon_set_palette(struct vc_data *c, unsigned char *table);
92 static int vgacon_scrolldelta(struct vc_data *c, int lines);
93 static int vgacon_set_origin(struct vc_data *c);
94 static void vgacon_save_screen(struct vc_data *c);
95 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines);
96 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse);
97 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
98 static unsigned long vgacon_uni_pagedir[2];
99
100
101 /* Description of the hardware situation */
102 static unsigned long vga_vram_base; /* Base of video memory */
103 static unsigned long vga_vram_end; /* End of video memory */
104 static u16 vga_video_port_reg; /* Video register select port */
105 static u16 vga_video_port_val; /* Video register value port */
106 static unsigned int vga_video_num_columns; /* Number of text columns */
107 static unsigned int vga_video_num_lines; /* Number of text lines */
108 static int vga_can_do_color = 0; /* Do we support colors? */
109 static unsigned int vga_default_font_height; /* Height of default screen font */
110 static unsigned char vga_video_type; /* Card type */
111 static unsigned char vga_hardscroll_enabled;
112 static unsigned char vga_hardscroll_user_enable = 1;
113 static unsigned char vga_font_is_default = 1;
114 static int vga_vesa_blanked;
115 static int vga_palette_blanked;
116 static int vga_is_gfx;
117 static int vga_512_chars;
118 static int vga_video_font_height;
119 static unsigned int vga_rolled_over = 0;
120
121
no_scroll(char * str)122 static int __init no_scroll(char *str)
123 {
124 /*
125 * Disabling scrollback is required for the Braillex ib80-piezo
126 * Braille reader made by F.H. Papenmeier (Germany).
127 * Use the "no-scroll" bootflag.
128 */
129 vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
130 return 1;
131 }
132
133 __setup("no-scroll", no_scroll);
134
135 /*
136 * By replacing the four outb_p with two back to back outw, we can reduce
137 * the window of opportunity to see text mislocated to the RHS of the
138 * console during heavy scrolling activity. However there is the remote
139 * possibility that some pre-dinosaur hardware won't like the back to back
140 * I/O. Since the Xservers get away with it, we should be able to as well.
141 */
write_vga(unsigned char reg,unsigned int val)142 static inline void write_vga(unsigned char reg, unsigned int val)
143 {
144 unsigned int v1, v2;
145 unsigned long flags;
146
147 /*
148 * ddprintk might set the console position from interrupt
149 * handlers, thus the write has to be IRQ-atomic.
150 */
151 spin_lock_irqsave(&vga_lock, flags);
152
153 #ifndef SLOW_VGA
154 v1 = reg + (val & 0xff00);
155 v2 = reg + 1 + ((val << 8) & 0xff00);
156 outw(v1, vga_video_port_reg);
157 outw(v2, vga_video_port_reg);
158 #else
159 outb_p(reg, vga_video_port_reg);
160 outb_p(val >> 8, vga_video_port_val);
161 outb_p(reg+1, vga_video_port_reg);
162 outb_p(val & 0xff, vga_video_port_val);
163 #endif
164 spin_unlock_irqrestore(&vga_lock, flags);
165 }
166
vgacon_startup(void)167 static const char __init *vgacon_startup(void)
168 {
169 const char *display_desc = NULL;
170 u16 saved1, saved2;
171 volatile u16 *p;
172
173 if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
174 no_vga:
175 #ifdef CONFIG_DUMMY_CONSOLE
176 conswitchp = &dummy_con;
177 return conswitchp->con_startup();
178 #else
179 return NULL;
180 #endif
181 }
182
183
184 vga_video_num_lines = ORIG_VIDEO_LINES;
185 vga_video_num_columns = ORIG_VIDEO_COLS;
186
187 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
188 {
189 vga_vram_base = 0xb0000;
190 vga_video_port_reg = 0x3b4;
191 vga_video_port_val = 0x3b5;
192 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
193 {
194 static struct resource ega_console_resource = { "ega", 0x3B0, 0x3BF };
195 vga_video_type = VIDEO_TYPE_EGAM;
196 vga_vram_end = 0xb8000;
197 display_desc = "EGA+";
198 request_resource(&ioport_resource, &ega_console_resource);
199 }
200 else
201 {
202 static struct resource mda1_console_resource = { "mda", 0x3B0, 0x3BB };
203 static struct resource mda2_console_resource = { "mda", 0x3BF, 0x3BF };
204 vga_video_type = VIDEO_TYPE_MDA;
205 vga_vram_end = 0xb2000;
206 display_desc = "*MDA";
207 request_resource(&ioport_resource, &mda1_console_resource);
208 request_resource(&ioport_resource, &mda2_console_resource);
209 vga_video_font_height = 14;
210 }
211 }
212 else /* If not, it is color. */
213 {
214 vga_can_do_color = 1;
215 vga_vram_base = 0xb8000;
216 vga_video_port_reg = 0x3d4;
217 vga_video_port_val = 0x3d5;
218 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
219 {
220 int i;
221
222 vga_vram_end = 0xc0000;
223
224 if (!ORIG_VIDEO_ISVGA) {
225 static struct resource ega_console_resource = { "ega", 0x3C0, 0x3DF };
226 vga_video_type = VIDEO_TYPE_EGAC;
227 display_desc = "EGA";
228 request_resource(&ioport_resource, &ega_console_resource);
229 } else {
230 static struct resource vga_console_resource = { "vga+", 0x3C0, 0x3DF };
231 vga_video_type = VIDEO_TYPE_VGAC;
232 display_desc = "VGA+";
233 request_resource(&ioport_resource, &vga_console_resource);
234
235 #ifdef VGA_CAN_DO_64KB
236 /*
237 * get 64K rather than 32K of video RAM.
238 * This doesn't actually work on all "VGA"
239 * controllers (it seems like setting MM=01
240 * and COE=1 isn't necessarily a good idea)
241 */
242 vga_vram_base = 0xa0000;
243 vga_vram_end = 0xb0000;
244 outb_p (6, 0x3ce) ;
245 outb_p (6, 0x3cf) ;
246 #endif
247
248 /*
249 * Normalise the palette registers, to point
250 * the 16 screen colours to the first 16
251 * DAC entries.
252 */
253
254 for (i=0; i<16; i++) {
255 inb_p (0x3da) ;
256 outb_p (i, 0x3c0) ;
257 outb_p (i, 0x3c0) ;
258 }
259 outb_p (0x20, 0x3c0) ;
260
261 /* now set the DAC registers back to their
262 * default values */
263
264 for (i=0; i<16; i++) {
265 outb_p (color_table[i], 0x3c8) ;
266 outb_p (default_red[i], 0x3c9) ;
267 outb_p (default_grn[i], 0x3c9) ;
268 outb_p (default_blu[i], 0x3c9) ;
269 }
270 }
271 }
272 else
273 {
274 static struct resource cga_console_resource = { "cga", 0x3D4, 0x3D5 };
275 vga_video_type = VIDEO_TYPE_CGA;
276 vga_vram_end = 0xba000;
277 display_desc = "*CGA";
278 request_resource(&ioport_resource, &cga_console_resource);
279 vga_video_font_height = 8;
280 }
281 }
282
283 vga_vram_base = VGA_MAP_MEM(vga_vram_base);
284 vga_vram_end = VGA_MAP_MEM(vga_vram_end);
285
286 /*
287 * Find out if there is a graphics card present.
288 * Are there smarter methods around?
289 */
290 p = (volatile u16 *)vga_vram_base;
291 saved1 = scr_readw(p);
292 saved2 = scr_readw(p + 1);
293 scr_writew(0xAA55, p);
294 scr_writew(0x55AA, p + 1);
295 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
296 scr_writew(saved1, p);
297 scr_writew(saved2, p + 1);
298 goto no_vga;
299 }
300 scr_writew(0x55AA, p);
301 scr_writew(0xAA55, p + 1);
302 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
303 scr_writew(saved1, p);
304 scr_writew(saved2, p + 1);
305 goto no_vga;
306 }
307 scr_writew(saved1, p);
308 scr_writew(saved2, p + 1);
309
310 if (vga_video_type == VIDEO_TYPE_EGAC
311 || vga_video_type == VIDEO_TYPE_VGAC
312 || vga_video_type == VIDEO_TYPE_EGAM) {
313 vga_hardscroll_enabled = vga_hardscroll_user_enable;
314 vga_default_font_height = ORIG_VIDEO_POINTS;
315 vga_video_font_height = ORIG_VIDEO_POINTS;
316 /* This may be suboptimal but is a safe bet - go with it */
317 video_scan_lines =
318 vga_video_font_height * vga_video_num_lines;
319 }
320 video_font_height = vga_video_font_height;
321
322 return display_desc;
323 }
324
vgacon_init(struct vc_data * c,int init)325 static void vgacon_init(struct vc_data *c, int init)
326 {
327 unsigned long p;
328
329 /* We cannot be loaded as a module, therefore init is always 1 */
330 c->vc_can_do_color = vga_can_do_color;
331 c->vc_cols = vga_video_num_columns;
332 c->vc_rows = vga_video_num_lines;
333 c->vc_complement_mask = 0x7700;
334 p = *c->vc_uni_pagedir_loc;
335 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
336 !--c->vc_uni_pagedir_loc[1])
337 con_free_unimap(c->vc_num);
338 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
339 vgacon_uni_pagedir[1]++;
340 if (!vgacon_uni_pagedir[0] && p)
341 con_set_default_unimap(c->vc_num);
342 }
343
vga_set_mem_top(struct vc_data * c)344 static inline void vga_set_mem_top(struct vc_data *c)
345 {
346 write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
347 }
348
vgacon_deinit(struct vc_data * c)349 static void vgacon_deinit(struct vc_data *c)
350 {
351 /* When closing the last console, reset video origin */
352 if (!--vgacon_uni_pagedir[1]) {
353 c->vc_visible_origin = vga_vram_base;
354 vga_set_mem_top(c);
355 con_free_unimap(c->vc_num);
356 }
357 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
358 con_set_default_unimap(c->vc_num);
359 }
360
vgacon_build_attr(struct vc_data * c,u8 color,u8 intensity,u8 blink,u8 underline,u8 reverse)361 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
362 {
363 u8 attr = color;
364
365 if (vga_can_do_color) {
366 if (underline)
367 attr = (attr & 0xf0) | c->vc_ulcolor;
368 else if (intensity == 0)
369 attr = (attr & 0xf0) | c->vc_halfcolor;
370 }
371 if (reverse)
372 attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77);
373 if (blink)
374 attr ^= 0x80;
375 if (intensity == 2)
376 attr ^= 0x08;
377 if (!vga_can_do_color) {
378 if (underline)
379 attr = (attr & 0xf8) | 0x01;
380 else if (intensity == 0)
381 attr = (attr & 0xf0) | 0x08;
382 }
383 return attr;
384 }
385
vgacon_invert_region(struct vc_data * c,u16 * p,int count)386 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
387 {
388 int col = vga_can_do_color;
389
390 while (count--) {
391 u16 a = scr_readw(p);
392 if (col)
393 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
394 else
395 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
396 scr_writew(a, p++);
397 }
398 }
399
vgacon_set_cursor_size(int xpos,int from,int to)400 static void vgacon_set_cursor_size(int xpos, int from, int to)
401 {
402 unsigned long flags;
403 int curs, cure;
404 static int lastfrom, lastto;
405
406 #ifdef TRIDENT_GLITCH
407 if (xpos<16) from--, to--;
408 #endif
409
410 if ((from == lastfrom) && (to == lastto)) return;
411 lastfrom = from; lastto = to;
412
413 spin_lock_irqsave(&vga_lock, flags);
414 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
415 curs = inb_p(vga_video_port_val);
416 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
417 cure = inb_p(vga_video_port_val);
418
419 curs = (curs & 0xc0) | from;
420 cure = (cure & 0xe0) | to;
421
422 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
423 outb_p(curs, vga_video_port_val);
424 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
425 outb_p(cure, vga_video_port_val);
426 spin_unlock_irqrestore(&vga_lock, flags);
427 }
428
vgacon_cursor(struct vc_data * c,int mode)429 static void vgacon_cursor(struct vc_data *c, int mode)
430 {
431 if (c->vc_origin != c->vc_visible_origin)
432 vgacon_scrolldelta(c, 0);
433 switch (mode) {
434 case CM_ERASE:
435 write_vga(14, (vga_vram_end - vga_vram_base - 1)/2);
436 break;
437
438 case CM_MOVE:
439 case CM_DRAW:
440 write_vga(14, (c->vc_pos-vga_vram_base)/2);
441 switch (c->vc_cursor_type & 0x0f) {
442 case CUR_UNDERLINE:
443 vgacon_set_cursor_size(c->vc_x,
444 video_font_height - (video_font_height < 10 ? 2 : 3),
445 video_font_height - (video_font_height < 10 ? 1 : 2));
446 break;
447 case CUR_TWO_THIRDS:
448 vgacon_set_cursor_size(c->vc_x,
449 video_font_height / 3,
450 video_font_height - (video_font_height < 10 ? 1 : 2));
451 break;
452 case CUR_LOWER_THIRD:
453 vgacon_set_cursor_size(c->vc_x,
454 (video_font_height*2) / 3,
455 video_font_height - (video_font_height < 10 ? 1 : 2));
456 break;
457 case CUR_LOWER_HALF:
458 vgacon_set_cursor_size(c->vc_x,
459 video_font_height / 2,
460 video_font_height - (video_font_height < 10 ? 1 : 2));
461 break;
462 case CUR_NONE:
463 vgacon_set_cursor_size(c->vc_x, 31, 30);
464 break;
465 default:
466 vgacon_set_cursor_size(c->vc_x, 1, video_font_height);
467 break;
468 }
469 break;
470 }
471 }
472
vgacon_switch(struct vc_data * c)473 static int vgacon_switch(struct vc_data *c)
474 {
475 /*
476 * We need to save screen size here as it's the only way
477 * we can spot the screen has been resized and we need to
478 * set size of freshly allocated screens ourselves.
479 */
480 vga_video_num_columns = c->vc_cols;
481 vga_video_num_lines = c->vc_rows;
482 if (!vga_is_gfx)
483 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size);
484 return 0; /* Redrawing not needed */
485 }
486
vga_set_palette(struct vc_data * c,unsigned char * table)487 static void vga_set_palette(struct vc_data *c, unsigned char *table)
488 {
489 int i, j ;
490
491 for (i=j=0; i<16; i++) {
492 outb_p (table[i], dac_reg) ;
493 outb_p (c->vc_palette[j++]>>2, dac_val) ;
494 outb_p (c->vc_palette[j++]>>2, dac_val) ;
495 outb_p (c->vc_palette[j++]>>2, dac_val) ;
496 }
497 }
498
vgacon_set_palette(struct vc_data * c,unsigned char * table)499 static int vgacon_set_palette(struct vc_data *c, unsigned char *table)
500 {
501 #ifdef CAN_LOAD_PALETTE
502 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(c))
503 return -EINVAL;
504 vga_set_palette(c, table);
505 return 0;
506 #else
507 return -EINVAL;
508 #endif
509 }
510
511 /* structure holding original VGA register settings */
512 static struct {
513 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
514 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
515 unsigned char CrtMiscIO; /* Miscellaneous register */
516 unsigned char HorizontalTotal; /* CRT-Controller:00h */
517 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
518 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
519 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
520 unsigned char Overflow; /* CRT-Controller:07h */
521 unsigned char StartVertRetrace; /* CRT-Controller:10h */
522 unsigned char EndVertRetrace; /* CRT-Controller:11h */
523 unsigned char ModeControl; /* CRT-Controller:17h */
524 unsigned char ClockingMode; /* Seq-Controller:01h */
525 } vga_state;
526
vga_vesa_blank(int mode)527 static void vga_vesa_blank(int mode)
528 {
529 /* save original values of VGA controller registers */
530 if(!vga_vesa_blanked) {
531 spin_lock_irq(&vga_lock);
532 vga_state.SeqCtrlIndex = inb_p(seq_port_reg);
533 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
534 vga_state.CrtMiscIO = inb_p(video_misc_rd);
535 spin_unlock_irq(&vga_lock);
536
537 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
538 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
539 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
540 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
541 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
542 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
543 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
544 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
545 outb_p(0x07,vga_video_port_reg); /* Overflow */
546 vga_state.Overflow = inb_p(vga_video_port_val);
547 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
548 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
549 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
550 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
551 outb_p(0x17,vga_video_port_reg); /* ModeControl */
552 vga_state.ModeControl = inb_p(vga_video_port_val);
553 outb_p(0x01,seq_port_reg); /* ClockingMode */
554 vga_state.ClockingMode = inb_p(seq_port_val);
555 }
556
557 /* assure that video is enabled */
558 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
559 spin_lock_irq(&vga_lock);
560 outb_p(0x01,seq_port_reg);
561 outb_p(vga_state.ClockingMode | 0x20,seq_port_val);
562
563 /* test for vertical retrace in process.... */
564 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
565 outb_p(vga_state.CrtMiscIO & 0xef,video_misc_wr);
566
567 /*
568 * Set <End of vertical retrace> to minimum (0) and
569 * <Start of vertical Retrace> to maximum (incl. overflow)
570 * Result: turn off vertical sync (VSync) pulse.
571 */
572 if (mode & VESA_VSYNC_SUSPEND) {
573 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
574 outb_p(0xff,vga_video_port_val); /* maximum value */
575 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
576 outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
577 outb_p(0x07,vga_video_port_reg); /* Overflow */
578 outb_p(vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
579 }
580
581 if (mode & VESA_HSYNC_SUSPEND) {
582 /*
583 * Set <End of horizontal retrace> to minimum (0) and
584 * <Start of horizontal Retrace> to maximum
585 * Result: turn off horizontal sync (HSync) pulse.
586 */
587 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
588 outb_p(0xff,vga_video_port_val); /* maximum */
589 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
590 outb_p(0x00,vga_video_port_val); /* minimum (0) */
591 }
592
593 /* restore both index registers */
594 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
595 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
596 spin_unlock_irq(&vga_lock);
597 }
598
vga_vesa_unblank(void)599 static void vga_vesa_unblank(void)
600 {
601 /* restore original values of VGA controller registers */
602 spin_lock_irq(&vga_lock);
603 outb_p(vga_state.CrtMiscIO,video_misc_wr);
604
605 outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
606 outb_p(vga_state.HorizontalTotal,vga_video_port_val);
607 outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
608 outb_p(vga_state.HorizDisplayEnd,vga_video_port_val);
609 outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
610 outb_p(vga_state.StartHorizRetrace,vga_video_port_val);
611 outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
612 outb_p(vga_state.EndHorizRetrace,vga_video_port_val);
613 outb_p(0x07,vga_video_port_reg); /* Overflow */
614 outb_p(vga_state.Overflow,vga_video_port_val);
615 outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
616 outb_p(vga_state.StartVertRetrace,vga_video_port_val);
617 outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
618 outb_p(vga_state.EndVertRetrace,vga_video_port_val);
619 outb_p(0x17,vga_video_port_reg); /* ModeControl */
620 outb_p(vga_state.ModeControl,vga_video_port_val);
621 outb_p(0x01,seq_port_reg); /* ClockingMode */
622 outb_p(vga_state.ClockingMode,seq_port_val);
623
624 /* restore index/control registers */
625 outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
626 outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
627 spin_unlock_irq(&vga_lock);
628 }
629
vga_pal_blank(void)630 static void vga_pal_blank(void)
631 {
632 int i;
633
634 for (i=0; i<16; i++) {
635 outb_p (i, dac_reg) ;
636 outb_p (0, dac_val) ;
637 outb_p (0, dac_val) ;
638 outb_p (0, dac_val) ;
639 }
640 }
641
vgacon_blank(struct vc_data * c,int blank)642 static int vgacon_blank(struct vc_data *c, int blank)
643 {
644 switch (blank) {
645 case 0: /* Unblank */
646 if (vga_vesa_blanked) {
647 vga_vesa_unblank();
648 vga_vesa_blanked = 0;
649 }
650 if (vga_palette_blanked) {
651 vga_set_palette(c, color_table);
652 vga_palette_blanked = 0;
653 return 0;
654 }
655 vga_is_gfx = 0;
656 /* Tell console.c that it has to restore the screen itself */
657 return 1;
658 case 1: /* Normal blanking */
659 if (vga_video_type == VIDEO_TYPE_VGAC) {
660 vga_pal_blank();
661 vga_palette_blanked = 1;
662 return 0;
663 }
664 vgacon_set_origin(c);
665 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
666 return 1;
667 case -1: /* Entering graphic mode */
668 scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size);
669 vga_is_gfx = 1;
670 return 1;
671 default: /* VESA blanking */
672 if (vga_video_type == VIDEO_TYPE_VGAC) {
673 vga_vesa_blank(blank-1);
674 vga_vesa_blanked = blank;
675 }
676 return 0;
677 }
678 }
679
680 /*
681 * PIO_FONT support.
682 *
683 * The font loading code goes back to the codepage package by
684 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
685 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
686 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
687 *
688 * Change for certain monochrome monitors by Yury Shevchuck
689 * (sizif@botik.yaroslavl.su).
690 */
691
692 #ifdef CAN_LOAD_EGA_FONTS
693
694 #define colourmap 0xa0000
695 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
696 should use 0xA0000 for the bwmap as well.. */
697 #define blackwmap 0xa0000
698 #define cmapsz 8192
699
700 static int
vgacon_do_font_op(char * arg,int set,int ch512)701 vgacon_do_font_op(char *arg, int set, int ch512)
702 {
703 int i;
704 char *charmap;
705 int beg;
706 unsigned short video_port_status = vga_video_port_reg + 6;
707 int font_select = 0x00;
708
709 if (vga_video_type != VIDEO_TYPE_EGAM) {
710 charmap = (char *)VGA_MAP_MEM(colourmap);
711 beg = 0x0e;
712 #ifdef VGA_CAN_DO_64KB
713 if (vga_video_type == VIDEO_TYPE_VGAC)
714 beg = 0x06;
715 #endif
716 } else {
717 charmap = (char *)VGA_MAP_MEM(blackwmap);
718 beg = 0x0a;
719 }
720
721 #ifdef BROKEN_GRAPHICS_PROGRAMS
722 /*
723 * All fonts are loaded in slot 0 (0:1 for 512 ch)
724 */
725
726 if (!arg)
727 return -EINVAL; /* Return to default font not supported */
728
729 vga_font_is_default = 0;
730 font_select = ch512 ? 0x04 : 0x00;
731 #else
732 /*
733 * The default font is kept in slot 0 and is never touched.
734 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
735 */
736
737 if (set) {
738 vga_font_is_default = !arg;
739 if (!arg)
740 ch512 = 0; /* Default font is always 256 */
741 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
742 }
743
744 if ( !vga_font_is_default )
745 charmap += 4*cmapsz;
746 #endif
747
748 spin_lock_irq(&vga_lock);
749 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
750 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
751 outb_p( 0x02, seq_port_reg );
752 outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
753 outb_p( 0x04, seq_port_reg );
754 outb_p( 0x07, seq_port_val ); /* Sequential addressing */
755 outb_p( 0x00, seq_port_reg );
756 outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
757
758 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
759 outb_p( 0x02, gr_port_val ); /* select map 2 */
760 outb_p( 0x05, gr_port_reg );
761 outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
762 outb_p( 0x06, gr_port_reg );
763 outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
764 spin_unlock_irq(&vga_lock);
765
766 if (arg) {
767 if (set)
768 for (i=0; i<cmapsz ; i++)
769 vga_writeb(arg[i], charmap + i);
770 else
771 for (i=0; i<cmapsz ; i++)
772 arg[i] = vga_readb(charmap + i);
773
774 /*
775 * In 512-character mode, the character map is not contiguous if
776 * we want to remain EGA compatible -- which we do
777 */
778
779 if (ch512) {
780 charmap += 2*cmapsz;
781 arg += cmapsz;
782 if (set)
783 for (i=0; i<cmapsz ; i++)
784 vga_writeb(arg[i], charmap+i);
785 else
786 for (i=0; i<cmapsz ; i++)
787 arg[i] = vga_readb(charmap+i);
788 }
789 }
790
791 spin_lock_irq(&vga_lock);
792 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
793 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
794 outb_p( 0x02, seq_port_reg );
795 outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
796 outb_p( 0x04, seq_port_reg );
797 outb_p( 0x03, seq_port_val ); /* odd-even addressing */
798 if (set) {
799 outb_p( 0x03, seq_port_reg ); /* Character Map Select */
800 outb_p( font_select, seq_port_val );
801 }
802 outb_p( 0x00, seq_port_reg );
803 outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
804
805 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
806 outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
807 outb_p( 0x05, gr_port_reg );
808 outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
809 outb_p( 0x06, gr_port_reg );
810 outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */
811
812 /* if 512 char mode is already enabled don't re-enable it. */
813 if ((set)&&(ch512!=vga_512_chars)) { /* attribute controller */
814 int i;
815 for(i=0; i<MAX_NR_CONSOLES; i++) {
816 struct vc_data *c = vc_cons[i].d;
817 if (c && c->vc_sw == &vga_con)
818 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
819 }
820 vga_512_chars=ch512;
821 /* 256-char: enable intensity bit
822 512-char: disable intensity bit */
823 inb_p( video_port_status ); /* clear address flip-flop */
824 outb_p ( 0x12, attrib_port ); /* color plane enable register */
825 outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
826 /* Wilton (1987) mentions the following; I don't know what
827 it means, but it works, and it appears necessary */
828 inb_p( video_port_status );
829 outb_p ( 0x20, attrib_port );
830 }
831 spin_unlock_irq(&vga_lock);
832 return 0;
833 }
834
835 /*
836 * Adjust the screen to fit a font of a certain height
837 */
838 static int
vgacon_adjust_height(unsigned fontheight)839 vgacon_adjust_height(unsigned fontheight)
840 {
841 int rows, maxscan;
842 unsigned char ovr, vde, fsr;
843
844 if (fontheight == vga_video_font_height)
845 return 0;
846
847 vga_video_font_height = video_font_height = fontheight;
848
849 rows = video_scan_lines/fontheight; /* Number of video rows we end up with */
850 maxscan = rows*fontheight - 1; /* Scan lines to actually display-1 */
851
852 /* Reprogram the CRTC for the new font size
853 Note: the attempt to read the overflow register will fail
854 on an EGA, but using 0xff for the previous value appears to
855 be OK for EGA text modes in the range 257-512 scan lines, so I
856 guess we don't need to worry about it.
857
858 The same applies for the spill bits in the font size and cursor
859 registers; they are write-only on EGA, but it appears that they
860 are all don't care bits on EGA, so I guess it doesn't matter. */
861
862 spin_lock_irq(&vga_lock);
863 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
864 ovr = inb_p(vga_video_port_val);
865 outb_p( 0x09, vga_video_port_reg ); /* Font size register */
866 fsr = inb_p(vga_video_port_val);
867 spin_unlock_irq(&vga_lock);
868
869 vde = maxscan & 0xff; /* Vertical display end reg */
870 ovr = (ovr & 0xbd) + /* Overflow register */
871 ((maxscan & 0x100) >> 7) +
872 ((maxscan & 0x200) >> 3);
873 fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */
874
875 spin_lock_irq(&vga_lock);
876 outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
877 outb_p( ovr, vga_video_port_val );
878 outb_p( 0x09, vga_video_port_reg ); /* Font size */
879 outb_p( fsr, vga_video_port_val );
880 outb_p( 0x12, vga_video_port_reg ); /* Vertical display limit */
881 outb_p( vde, vga_video_port_val );
882 spin_unlock_irq(&vga_lock);
883
884 vc_resize_all(rows, 0); /* Adjust console size */
885 return 0;
886 }
887
vgacon_font_op(struct vc_data * c,struct console_font_op * op)888 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
889 {
890 int rc;
891
892 if (vga_video_type < VIDEO_TYPE_EGAM)
893 return -EINVAL;
894
895 if (op->op == KD_FONT_OP_SET) {
896 if (op->width != 8 || (op->charcount != 256 && op->charcount != 512))
897 return -EINVAL;
898 rc = vgacon_do_font_op(op->data, 1, op->charcount == 512);
899 if (!rc && !(op->flags & KD_FONT_FLAG_DONT_RECALC))
900 rc = vgacon_adjust_height(op->height);
901 } else if (op->op == KD_FONT_OP_GET) {
902 op->width = 8;
903 op->height = vga_video_font_height;
904 op->charcount = vga_512_chars ? 512 : 256;
905 if (!op->data) return 0;
906 rc = vgacon_do_font_op(op->data, 0, 0);
907 } else
908 rc = -ENOSYS;
909 return rc;
910 }
911
912 #else
913
vgacon_font_op(struct vc_data * c,struct console_font_op * op)914 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
915 {
916 return -ENOSYS;
917 }
918
919 #endif
920
vgacon_scrolldelta(struct vc_data * c,int lines)921 static int vgacon_scrolldelta(struct vc_data *c, int lines)
922 {
923 if (!lines) /* Turn scrollback off */
924 c->vc_visible_origin = c->vc_origin;
925 else {
926 int vram_size = vga_vram_end - vga_vram_base;
927 int margin = c->vc_size_row * 4;
928 int ul, we, p, st;
929
930 if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) {
931 ul = c->vc_scr_end - vga_vram_base;
932 we = vga_rolled_over + c->vc_size_row;
933 } else {
934 ul = 0;
935 we = vram_size;
936 }
937 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row;
938 st = (c->vc_origin - vga_vram_base - ul + we) % we;
939 if (p < margin)
940 p = 0;
941 if (p > st - margin)
942 p = st;
943 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
944 }
945 vga_set_mem_top(c);
946 return 1;
947 }
948
vgacon_set_origin(struct vc_data * c)949 static int vgacon_set_origin(struct vc_data *c)
950 {
951 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
952 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
953 return 0;
954 c->vc_origin = c->vc_visible_origin = vga_vram_base;
955 vga_set_mem_top(c);
956 vga_rolled_over = 0;
957 return 1;
958 }
959
vgacon_save_screen(struct vc_data * c)960 static void vgacon_save_screen(struct vc_data *c)
961 {
962 static int vga_bootup_console = 0;
963
964 if (!vga_bootup_console) {
965 /* This is a gross hack, but here is the only place we can
966 * set bootup console parameters without messing up generic
967 * console initialization routines.
968 */
969 vga_bootup_console = 1;
970 c->vc_x = ORIG_X;
971 c->vc_y = ORIG_Y;
972 }
973 if (!vga_is_gfx)
974 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size);
975 }
976
vgacon_scroll(struct vc_data * c,int t,int b,int dir,int lines)977 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
978 {
979 unsigned long oldo;
980 unsigned int delta;
981
982 if (t || b != c->vc_rows || vga_is_gfx)
983 return 0;
984
985 if (c->vc_origin != c->vc_visible_origin)
986 vgacon_scrolldelta(c, 0);
987
988 if (!vga_hardscroll_enabled || lines >= c->vc_rows/2)
989 return 0;
990
991 oldo = c->vc_origin;
992 delta = lines * c->vc_size_row;
993 if (dir == SM_UP) {
994 if (c->vc_scr_end + delta >= vga_vram_end) {
995 scr_memcpyw((u16 *)vga_vram_base,
996 (u16 *)(oldo + delta),
997 c->vc_screenbuf_size - delta);
998 c->vc_origin = vga_vram_base;
999 vga_rolled_over = oldo - vga_vram_base;
1000 } else
1001 c->vc_origin += delta;
1002 scr_memsetw((u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta);
1003 } else {
1004 if (oldo - delta < vga_vram_base) {
1005 scr_memmovew((u16 *)(vga_vram_end - c->vc_screenbuf_size + delta),
1006 (u16 *)oldo,
1007 c->vc_screenbuf_size - delta);
1008 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1009 vga_rolled_over = 0;
1010 } else
1011 c->vc_origin -= delta;
1012 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1013 scr_memsetw((u16 *)(c->vc_origin), c->vc_video_erase_char, delta);
1014 }
1015 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1016 c->vc_visible_origin = c->vc_origin;
1017 vga_set_mem_top(c);
1018 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1019 return 1;
1020 }
1021
1022
1023 /*
1024 * The console `switch' structure for the VGA based console
1025 */
1026
vgacon_dummy(struct vc_data * c)1027 static int vgacon_dummy(struct vc_data *c)
1028 {
1029 return 0;
1030 }
1031
1032 #define DUMMY (void *) vgacon_dummy
1033
1034 const struct consw vga_con = {
1035 con_startup: vgacon_startup,
1036 con_init: vgacon_init,
1037 con_deinit: vgacon_deinit,
1038 con_clear: DUMMY,
1039 con_putc: DUMMY,
1040 con_putcs: DUMMY,
1041 con_cursor: vgacon_cursor,
1042 con_scroll: vgacon_scroll,
1043 con_bmove: DUMMY,
1044 con_switch: vgacon_switch,
1045 con_blank: vgacon_blank,
1046 con_font_op: vgacon_font_op,
1047 con_set_palette: vgacon_set_palette,
1048 con_scrolldelta: vgacon_scrolldelta,
1049 con_set_origin: vgacon_set_origin,
1050 con_save_screen: vgacon_save_screen,
1051 con_build_attr: vgacon_build_attr,
1052 con_invert_region: vgacon_invert_region,
1053 };
1054
1055 MODULE_LICENSE("GPL");
1056