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