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