1 // Standard VGA driver code
3 // Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
8 #include "stdvga.h" // stdvga_init
9 #include "ioport.h" // outb
10 #include "farptr.h" // SET_FARVAR
11 #include "biosvar.h" // GET_GLOBAL
12 #include "util.h" // memcpy_far
13 #include "vbe.h" // VBE_RETURN_STATUS_FAILED
16 // * replace direct in/out calls with wrapper functions
19 /****************************************************************
21 ****************************************************************/
24 stdvga_screen_disable(void)
26 inb(VGAREG_ACTL_RESET);
27 outb(0x00, VGAREG_ACTL_ADDRESS);
31 stdvga_screen_enable(void)
33 inb(VGAREG_ACTL_RESET);
34 outb(0x20, VGAREG_ACTL_ADDRESS);
38 stdvga_set_border_color(u8 color)
40 inb(VGAREG_ACTL_RESET);
41 outb(0x00, VGAREG_ACTL_ADDRESS);
45 outb(v1, VGAREG_ACTL_WRITE_DATA);
49 for (i = 1; i < 4; i++) {
50 outb(i, VGAREG_ACTL_ADDRESS);
52 u8 cur = inb(VGAREG_ACTL_READ_DATA);
55 outb(cur, VGAREG_ACTL_WRITE_DATA);
57 outb(0x20, VGAREG_ACTL_ADDRESS);
61 stdvga_set_overscan_border_color(u8 color)
63 inb(VGAREG_ACTL_RESET);
64 outb(0x11, VGAREG_ACTL_ADDRESS);
65 outb(color, VGAREG_ACTL_WRITE_DATA);
66 outb(0x20, VGAREG_ACTL_ADDRESS);
70 stdvga_get_overscan_border_color(void)
72 inb(VGAREG_ACTL_RESET);
73 outb(0x11, VGAREG_ACTL_ADDRESS);
74 u8 v = inb(VGAREG_ACTL_READ_DATA);
75 inb(VGAREG_ACTL_RESET);
76 outb(0x20, VGAREG_ACTL_ADDRESS);
81 stdvga_set_palette(u8 palid)
83 inb(VGAREG_ACTL_RESET);
86 for (i = 1; i < 4; i++) {
87 outb(i, VGAREG_ACTL_ADDRESS);
89 u8 v = inb(VGAREG_ACTL_READ_DATA);
92 outb(v, VGAREG_ACTL_WRITE_DATA);
94 outb(0x20, VGAREG_ACTL_ADDRESS);
98 stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
100 inb(VGAREG_ACTL_RESET);
102 for (i = 0; i < 0x10; i++) {
103 outb(i, VGAREG_ACTL_ADDRESS);
104 u8 val = GET_FARVAR(seg, *data_far);
105 outb(val, VGAREG_ACTL_WRITE_DATA);
108 outb(0x11, VGAREG_ACTL_ADDRESS);
109 outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
110 outb(0x20, VGAREG_ACTL_ADDRESS);
114 stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
117 for (i = 0; i < 0x10; i++) {
118 inb(VGAREG_ACTL_RESET);
119 outb(i, VGAREG_ACTL_ADDRESS);
120 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
123 inb(VGAREG_ACTL_RESET);
124 outb(0x11, VGAREG_ACTL_ADDRESS);
125 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
126 inb(VGAREG_ACTL_RESET);
127 outb(0x20, VGAREG_ACTL_ADDRESS);
131 stdvga_toggle_intensity(u8 flag)
133 inb(VGAREG_ACTL_RESET);
134 outb(0x10, VGAREG_ACTL_ADDRESS);
135 u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
136 outb(val, VGAREG_ACTL_WRITE_DATA);
137 outb(0x20, VGAREG_ACTL_ADDRESS);
141 stdvga_select_video_dac_color_page(u8 flag, u8 data)
143 inb(VGAREG_ACTL_RESET);
144 outb(0x10, VGAREG_ACTL_ADDRESS);
145 u8 val = inb(VGAREG_ACTL_READ_DATA);
146 if (!(flag & 0x01)) {
147 // select paging mode
148 val = (val & 0x7f) | (data << 7);
149 outb(val, VGAREG_ACTL_WRITE_DATA);
150 outb(0x20, VGAREG_ACTL_ADDRESS);
154 inb(VGAREG_ACTL_RESET);
155 outb(0x14, VGAREG_ACTL_ADDRESS);
159 outb(data, VGAREG_ACTL_WRITE_DATA);
160 outb(0x20, VGAREG_ACTL_ADDRESS);
164 stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
166 inb(VGAREG_ACTL_RESET);
167 outb(0x10, VGAREG_ACTL_ADDRESS);
168 u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
170 inb(VGAREG_ACTL_RESET);
171 outb(0x14, VGAREG_ACTL_ADDRESS);
172 u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
176 inb(VGAREG_ACTL_RESET);
177 outb(0x20, VGAREG_ACTL_ADDRESS);
184 /****************************************************************
186 ****************************************************************/
189 stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
191 /* XXX: check this */
192 SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
193 SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
194 SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
195 stdvga_dac_read(seg, info->dac, 0, 256);
196 SET_FARVAR(seg, info->color_select, 0);
200 stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
202 outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
203 stdvga_dac_write(seg, info->dac, 0, 256);
204 outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
208 stdvga_perform_gray_scale_summing(u16 start, u16 count)
210 stdvga_screen_disable();
212 for (i = start; i < start+count; i++) {
214 stdvga_dac_read(GET_SEG(SS), rgb, i, 1);
216 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
217 u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
218 if (intensity > 0x3f)
221 stdvga_dac_write(GET_SEG(SS), rgb, i, 1);
223 stdvga_screen_enable();
227 /****************************************************************
229 ****************************************************************/
232 stdvga_set_text_block_specifier(u8 spec)
234 outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
238 /****************************************************************
240 ****************************************************************/
243 get_font_access(void)
245 outw(0x0100, VGAREG_SEQU_ADDRESS);
246 outw(0x0402, VGAREG_SEQU_ADDRESS);
247 outw(0x0704, VGAREG_SEQU_ADDRESS);
248 outw(0x0300, VGAREG_SEQU_ADDRESS);
249 outw(0x0204, VGAREG_GRDC_ADDRESS);
250 outw(0x0005, VGAREG_GRDC_ADDRESS);
251 outw(0x0406, VGAREG_GRDC_ADDRESS);
255 release_font_access(void)
257 outw(0x0100, VGAREG_SEQU_ADDRESS);
258 outw(0x0302, VGAREG_SEQU_ADDRESS);
259 outw(0x0304, VGAREG_SEQU_ADDRESS);
260 outw(0x0300, VGAREG_SEQU_ADDRESS);
261 u16 v = (inb(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
262 outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
263 outw(0x0004, VGAREG_GRDC_ADDRESS);
264 outw(0x1005, VGAREG_GRDC_ADDRESS);
268 stdvga_load_font(u16 seg, void *src_far, u16 count
269 , u16 start, u8 destflags, u8 fontsize)
272 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
273 void *dest_far = (void*)(blockaddr + start*32);
275 for (i = 0; i < count; i++)
276 memcpy_far(SEG_GRAPH, dest_far + i*32
277 , seg, src_far + i*fontsize, fontsize);
278 release_font_access();
282 /****************************************************************
284 ****************************************************************/
287 stdvga_get_crtc(void)
289 if (stdvga_misc_read() & 1)
290 return VGAREG_VGA_CRTC_ADDRESS;
291 return VGAREG_MDA_CRTC_ADDRESS;
295 stdvga_set_cursor_shape(u8 start, u8 end)
297 u16 crtc_addr = stdvga_get_crtc();
298 outb(0x0a, crtc_addr);
299 outb(start, crtc_addr + 1);
300 outb(0x0b, crtc_addr);
301 outb(end, crtc_addr + 1);
305 stdvga_set_active_page(u16 address)
307 u16 crtc_addr = stdvga_get_crtc();
308 outb(0x0c, crtc_addr);
309 outb((address & 0xff00) >> 8, crtc_addr + 1);
310 outb(0x0d, crtc_addr);
311 outb(address & 0x00ff, crtc_addr + 1);
315 stdvga_set_cursor_pos(u16 address)
317 u16 crtc_addr = stdvga_get_crtc();
318 outb(0x0e, crtc_addr);
319 outb((address & 0xff00) >> 8, crtc_addr + 1);
320 outb(0x0f, crtc_addr);
321 outb(address & 0x00ff, crtc_addr + 1);
325 stdvga_set_scan_lines(u8 lines)
327 u16 crtc_addr = stdvga_get_crtc();
328 outb(0x09, crtc_addr);
329 u8 crtc_r9 = inb(crtc_addr + 1);
330 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
331 outb(crtc_r9, crtc_addr + 1);
334 // Get vertical display end
338 u16 crtc_addr = stdvga_get_crtc();
339 outb(0x12, crtc_addr);
340 u16 vde = inb(crtc_addr + 1);
341 outb(0x07, crtc_addr);
342 u8 ovl = inb(crtc_addr + 1);
343 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
348 /****************************************************************
349 * Save/Restore/Set state
350 ****************************************************************/
353 stdvga_save_state(u16 seg, struct saveVideoHardware *info)
355 u16 crtc_addr = stdvga_get_crtc();
356 SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
357 SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
358 SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
359 inb(VGAREG_ACTL_RESET);
360 u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
361 SET_FARVAR(seg, info->actl_index, ar_index);
362 SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
365 for (i=0; i<4; i++) {
366 outb(i+1, VGAREG_SEQU_ADDRESS);
367 SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
369 outb(0, VGAREG_SEQU_ADDRESS);
370 SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
372 for (i=0; i<25; i++) {
374 SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
377 for (i=0; i<20; i++) {
378 inb(VGAREG_ACTL_RESET);
379 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
380 SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
382 inb(VGAREG_ACTL_RESET);
384 for (i=0; i<9; i++) {
385 outb(i, VGAREG_GRDC_ADDRESS);
386 SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
389 SET_FARVAR(seg, info->crtc_addr, crtc_addr);
391 /* XXX: read plane latches */
393 SET_FARVAR(seg, info->plane_latch[i], 0);
397 stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
399 // Reset Attribute Ctl flip-flop
400 inb(VGAREG_ACTL_RESET);
402 u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
405 for (i=0; i<4; i++) {
406 outb(i+1, VGAREG_SEQU_ADDRESS);
407 outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
409 outb(0, VGAREG_SEQU_ADDRESS);
410 outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
412 // Disable CRTC write protection
413 outw(0x0011, crtc_addr);
418 outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
420 // select crtc base address
421 u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
422 if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
424 outb(v, VGAREG_WRITE_MISC_OUTPUT);
426 // enable write protection if needed
427 outb(0x11, crtc_addr);
428 outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
431 u16 ar_index = GET_FARVAR(seg, info->actl_index);
432 inb(VGAREG_ACTL_RESET);
433 for (i=0; i<20; i++) {
434 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
435 outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
437 outb(ar_index, VGAREG_ACTL_ADDRESS);
438 inb(VGAREG_ACTL_RESET);
440 for (i=0; i<9; i++) {
441 outb(i, VGAREG_GRDC_ADDRESS);
442 outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
445 outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
446 outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
447 outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
448 outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
452 clear_screen(struct vgamode_s *vmode_g)
454 switch (GET_GLOBAL(vmode_g->memmodel)) {
456 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
459 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
462 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
463 // but it should always be 0xf anyway.
464 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
469 stdvga_set_mode(int mode, int flags)
471 // find the entry in the video modes
472 struct vgamode_s *vmode_g = stdvga_find_mode(mode);
473 dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
475 return VBE_RETURN_STATUS_FAILED;
476 struct stdvga_mode_s *stdmode_g = container_of(
477 vmode_g, struct stdvga_mode_s, info);
479 // if palette loading (bit 3 of modeset ctl = 0)
480 if (!(flags & MF_NOPALETTE)) { // Set the PEL mask
481 stdvga_pelmask_write(GET_GLOBAL(stdmode_g->pelmask));
483 // From which palette
484 u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
485 u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
487 // Always 256*3 values
488 stdvga_dac_write(get_global_seg(), palette_g, 0, palsize);
490 for (i = palsize; i < 0x0100; i++) {
491 static u8 rgb[3] VAR16;
492 stdvga_dac_write(get_global_seg(), rgb, i, 1);
495 if (flags & MF_GRAYSUM)
496 stdvga_perform_gray_scale_summing(0x00, 0x100);
499 // Reset Attribute Ctl flip-flop
500 inb(VGAREG_ACTL_RESET);
503 u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
505 for (i = 0; i <= 0x13; i++) {
506 outb(i, VGAREG_ACTL_ADDRESS);
507 outb(GET_GLOBAL(regs[i]), VGAREG_ACTL_WRITE_DATA);
509 outb(0x14, VGAREG_ACTL_ADDRESS);
510 outb(0x00, VGAREG_ACTL_WRITE_DATA);
513 outb(0, VGAREG_SEQU_ADDRESS);
514 outb(0x03, VGAREG_SEQU_DATA);
515 regs = GET_GLOBAL(stdmode_g->sequ_regs);
516 for (i = 1; i <= 4; i++) {
517 outb(i, VGAREG_SEQU_ADDRESS);
518 outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
522 regs = GET_GLOBAL(stdmode_g->grdc_regs);
523 for (i = 0; i <= 8; i++) {
524 outb(i, VGAREG_GRDC_ADDRESS);
525 outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
528 // Set CRTC address VGA or MDA
529 u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
530 u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
532 crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
534 // Disable CRTC write protection
535 outw(0x0011, crtc_addr);
537 regs = GET_GLOBAL(stdmode_g->crtc_regs);
538 for (i = 0; i <= 0x18; i++) {
540 outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
543 // Set the misc register
544 outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
547 outb(0x20, VGAREG_ACTL_ADDRESS);
548 inb(VGAREG_ACTL_RESET);
551 if (!(flags & MF_NOCLEARMEM))
552 clear_screen(vmode_g);
554 // Write the fonts in memory
555 u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
556 if (memmodel == MM_TEXT)
557 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
559 // Setup BDA variables
560 modeswitch_set_bda(mode, flags, vmode_g);
566 /****************************************************************
568 ****************************************************************/
571 stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
573 SET_FARVAR(seg, *dest, 0xffff);
577 stdvga_enable_video_addressing(u8 disable)
579 u8 v = (disable & 1) ? 0x00 : 0x02;
580 u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
581 outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
587 // switch to color mode and enable CPU access 480 lines
588 outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
589 // more than 64k 3C4/04
590 outb(0x04, VGAREG_SEQU_ADDRESS);
591 outb(0x02, VGAREG_SEQU_DATA);