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" // vgahw_init
9 #include "ioport.h" // outb
10 #include "farptr.h" // SET_FARVAR
11 #include "biosvar.h" // GET_BDA
12 #include "vgabios.h" // VGAREG_*
15 // * replace direct in/out calls with wrapper functions
18 /****************************************************************
20 ****************************************************************/
23 vgahw_screen_disable(void)
25 inb(VGAREG_ACTL_RESET);
26 outb(0x00, VGAREG_ACTL_ADDRESS);
30 vgahw_screen_enable(void)
32 inb(VGAREG_ACTL_RESET);
33 outb(0x20, VGAREG_ACTL_ADDRESS);
37 vgahw_set_border_color(u8 color)
39 inb(VGAREG_ACTL_RESET);
40 outb(0x00, VGAREG_ACTL_ADDRESS);
44 outb(v1, VGAREG_ACTL_WRITE_DATA);
48 for (i = 1; i < 4; i++) {
49 outb(i, VGAREG_ACTL_ADDRESS);
51 u8 cur = inb(VGAREG_ACTL_READ_DATA);
54 outb(cur, VGAREG_ACTL_WRITE_DATA);
56 outb(0x20, VGAREG_ACTL_ADDRESS);
60 vgahw_set_overscan_border_color(u8 color)
62 inb(VGAREG_ACTL_RESET);
63 outb(0x11, VGAREG_ACTL_ADDRESS);
64 outb(color, VGAREG_ACTL_WRITE_DATA);
65 outb(0x20, VGAREG_ACTL_ADDRESS);
69 vgahw_get_overscan_border_color(void)
71 inb(VGAREG_ACTL_RESET);
72 outb(0x11, VGAREG_ACTL_ADDRESS);
73 u8 v = inb(VGAREG_ACTL_READ_DATA);
74 inb(VGAREG_ACTL_RESET);
75 outb(0x20, VGAREG_ACTL_ADDRESS);
80 vgahw_set_palette(u8 palid)
82 inb(VGAREG_ACTL_RESET);
85 for (i = 1; i < 4; i++) {
86 outb(i, VGAREG_ACTL_ADDRESS);
88 u8 v = inb(VGAREG_ACTL_READ_DATA);
91 outb(v, VGAREG_ACTL_WRITE_DATA);
93 outb(0x20, VGAREG_ACTL_ADDRESS);
97 vgahw_set_single_palette_reg(u8 reg, u8 val)
99 inb(VGAREG_ACTL_RESET);
100 outb(reg, VGAREG_ACTL_ADDRESS);
101 outb(val, VGAREG_ACTL_WRITE_DATA);
102 outb(0x20, VGAREG_ACTL_ADDRESS);
106 vgahw_get_single_palette_reg(u8 reg)
108 inb(VGAREG_ACTL_RESET);
109 outb(reg, VGAREG_ACTL_ADDRESS);
110 u8 v = inb(VGAREG_ACTL_READ_DATA);
111 inb(VGAREG_ACTL_RESET);
112 outb(0x20, VGAREG_ACTL_ADDRESS);
117 vgahw_set_all_palette_reg(u16 seg, u8 *data_far)
119 inb(VGAREG_ACTL_RESET);
121 for (i = 0; i < 0x10; i++) {
122 outb(i, VGAREG_ACTL_ADDRESS);
123 u8 val = GET_FARVAR(seg, *data_far);
124 outb(val, VGAREG_ACTL_WRITE_DATA);
127 outb(0x11, VGAREG_ACTL_ADDRESS);
128 outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
129 outb(0x20, VGAREG_ACTL_ADDRESS);
133 vgahw_get_all_palette_reg(u16 seg, u8 *data_far)
136 for (i = 0; i < 0x10; i++) {
137 inb(VGAREG_ACTL_RESET);
138 outb(i, VGAREG_ACTL_ADDRESS);
139 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
142 inb(VGAREG_ACTL_RESET);
143 outb(0x11, VGAREG_ACTL_ADDRESS);
144 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
145 inb(VGAREG_ACTL_RESET);
146 outb(0x20, VGAREG_ACTL_ADDRESS);
150 vgahw_toggle_intensity(u8 flag)
152 inb(VGAREG_ACTL_RESET);
153 outb(0x10, VGAREG_ACTL_ADDRESS);
154 u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
155 outb(val, VGAREG_ACTL_WRITE_DATA);
156 outb(0x20, VGAREG_ACTL_ADDRESS);
160 vgahw_select_video_dac_color_page(u8 flag, u8 data)
162 inb(VGAREG_ACTL_RESET);
163 outb(0x10, VGAREG_ACTL_ADDRESS);
164 u8 val = inb(VGAREG_ACTL_READ_DATA);
165 if (!(flag & 0x01)) {
166 // select paging mode
167 val = (val & 0x7f) | (data << 7);
168 outb(val, VGAREG_ACTL_WRITE_DATA);
169 outb(0x20, VGAREG_ACTL_ADDRESS);
173 inb(VGAREG_ACTL_RESET);
174 outb(0x14, VGAREG_ACTL_ADDRESS);
178 outb(data, VGAREG_ACTL_WRITE_DATA);
179 outb(0x20, VGAREG_ACTL_ADDRESS);
183 vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
185 inb(VGAREG_ACTL_RESET);
186 outb(0x10, VGAREG_ACTL_ADDRESS);
187 u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
189 inb(VGAREG_ACTL_RESET);
190 outb(0x14, VGAREG_ACTL_ADDRESS);
191 u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
195 inb(VGAREG_ACTL_RESET);
196 outb(0x20, VGAREG_ACTL_ADDRESS);
203 /****************************************************************
205 ****************************************************************/
208 vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
210 outb(start, VGAREG_DAC_WRITE_ADDRESS);
212 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
214 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
216 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
223 vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
225 outb(start, VGAREG_DAC_READ_ADDRESS);
227 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
229 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
231 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
238 vgahw_set_pel_mask(u8 val)
240 outb(val, VGAREG_PEL_MASK);
244 vgahw_get_pel_mask(void)
246 return inb(VGAREG_PEL_MASK);
250 vgahw_save_dac_state(u16 seg, struct saveDACcolors *info)
252 /* XXX: check this */
253 SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
254 SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
255 SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
256 vgahw_get_dac_regs(seg, info->dac, 0, 256);
257 SET_FARVAR(seg, info->color_select, 0);
261 vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info)
263 outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
264 vgahw_set_dac_regs(seg, info->dac, 0, 256);
265 outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
269 /****************************************************************
271 ****************************************************************/
274 vgahw_sequ_write(u8 index, u8 value)
276 outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
280 vgahw_grdc_write(u8 index, u8 value)
282 outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
286 vgahw_set_text_block_specifier(u8 spec)
288 outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
292 get_font_access(void)
294 outw(0x0100, VGAREG_SEQU_ADDRESS);
295 outw(0x0402, VGAREG_SEQU_ADDRESS);
296 outw(0x0704, VGAREG_SEQU_ADDRESS);
297 outw(0x0300, VGAREG_SEQU_ADDRESS);
298 outw(0x0204, VGAREG_GRDC_ADDRESS);
299 outw(0x0005, VGAREG_GRDC_ADDRESS);
300 outw(0x0406, VGAREG_GRDC_ADDRESS);
304 release_font_access(void)
306 outw(0x0100, VGAREG_SEQU_ADDRESS);
307 outw(0x0302, VGAREG_SEQU_ADDRESS);
308 outw(0x0304, VGAREG_SEQU_ADDRESS);
309 outw(0x0300, VGAREG_SEQU_ADDRESS);
310 u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
311 outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
312 outw(0x0004, VGAREG_GRDC_ADDRESS);
313 outw(0x1005, VGAREG_GRDC_ADDRESS);
317 /****************************************************************
319 ****************************************************************/
324 return GET_BDA(crtc_address);
328 vgahw_set_cursor_shape(u8 start, u8 end)
330 u16 crtc_addr = get_crtc();
331 outb(0x0a, crtc_addr);
332 outb(start, crtc_addr + 1);
333 outb(0x0b, crtc_addr);
334 outb(end, crtc_addr + 1);
338 vgahw_set_active_page(u16 address)
340 u16 crtc_addr = get_crtc();
341 outb(0x0c, crtc_addr);
342 outb((address & 0xff00) >> 8, crtc_addr + 1);
343 outb(0x0d, crtc_addr);
344 outb(address & 0x00ff, crtc_addr + 1);
348 vgahw_set_cursor_pos(u16 address)
350 u16 crtc_addr = get_crtc();
351 outb(0x0e, crtc_addr);
352 outb((address & 0xff00) >> 8, crtc_addr + 1);
353 outb(0x0f, crtc_addr);
354 outb(address & 0x00ff, crtc_addr + 1);
358 vgahw_set_scan_lines(u8 lines)
360 u16 crtc_addr = get_crtc();
361 outb(0x09, crtc_addr);
362 u8 crtc_r9 = inb(crtc_addr + 1);
363 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
364 outb(crtc_r9, crtc_addr + 1);
367 // Get vertical display end
371 u16 crtc_addr = get_crtc();
372 outb(0x12, crtc_addr);
373 u16 vde = inb(crtc_addr + 1);
374 outb(0x07, crtc_addr);
375 u8 ovl = inb(crtc_addr + 1);
376 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
381 /****************************************************************
382 * Save/Restore/Set state
383 ****************************************************************/
386 vgahw_save_state(u16 seg, struct saveVideoHardware *info)
388 u16 crtc_addr = get_crtc();
389 SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
390 SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
391 SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
392 inb(VGAREG_ACTL_RESET);
393 u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
394 SET_FARVAR(seg, info->actl_index, ar_index);
395 SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
398 for (i=0; i<4; i++) {
399 outb(i+1, VGAREG_SEQU_ADDRESS);
400 SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
402 outb(0, VGAREG_SEQU_ADDRESS);
403 SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
405 for (i=0; i<25; i++) {
407 SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
410 for (i=0; i<20; i++) {
411 inb(VGAREG_ACTL_RESET);
412 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
413 SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
415 inb(VGAREG_ACTL_RESET);
417 for (i=0; i<9; i++) {
418 outb(i, VGAREG_GRDC_ADDRESS);
419 SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
422 SET_FARVAR(seg, info->crtc_addr, crtc_addr);
424 /* XXX: read plane latches */
426 SET_FARVAR(seg, info->plane_latch[i], 0);
430 vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
432 // Reset Attribute Ctl flip-flop
433 inb(VGAREG_ACTL_RESET);
435 u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
438 for (i=0; i<4; i++) {
439 outb(i+1, VGAREG_SEQU_ADDRESS);
440 outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
442 outb(0, VGAREG_SEQU_ADDRESS);
443 outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
445 // Disable CRTC write protection
446 outw(0x0011, crtc_addr);
451 outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
453 // select crtc base address
454 u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
455 if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
457 outb(v, VGAREG_WRITE_MISC_OUTPUT);
459 // enable write protection if needed
460 outb(0x11, crtc_addr);
461 outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
464 u16 ar_index = GET_FARVAR(seg, info->actl_index);
465 inb(VGAREG_ACTL_RESET);
466 for (i=0; i<20; i++) {
467 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
468 outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
470 outb(ar_index, VGAREG_ACTL_ADDRESS);
471 inb(VGAREG_ACTL_RESET);
473 for (i=0; i<9; i++) {
474 outb(i, VGAREG_GRDC_ADDRESS);
475 outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
478 outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
479 outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
480 outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
481 outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
485 vgahw_set_mode(struct vgamode_s *vmode_g)
487 // Reset Attribute Ctl flip-flop
488 inb(VGAREG_ACTL_RESET);
491 u8 *regs = GET_GLOBAL(vmode_g->actl_regs);
493 for (i = 0; i <= 0x13; i++) {
494 outb(i, VGAREG_ACTL_ADDRESS);
495 outb(GET_GLOBAL(regs[i]), VGAREG_ACTL_WRITE_DATA);
497 outb(0x14, VGAREG_ACTL_ADDRESS);
498 outb(0x00, VGAREG_ACTL_WRITE_DATA);
501 outb(0, VGAREG_SEQU_ADDRESS);
502 outb(0x03, VGAREG_SEQU_DATA);
503 regs = GET_GLOBAL(vmode_g->sequ_regs);
504 for (i = 1; i <= 4; i++) {
505 outb(i, VGAREG_SEQU_ADDRESS);
506 outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
510 regs = GET_GLOBAL(vmode_g->grdc_regs);
511 for (i = 0; i <= 8; i++) {
512 outb(i, VGAREG_GRDC_ADDRESS);
513 outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
516 // Set CRTC address VGA or MDA
517 u8 miscreg = GET_GLOBAL(vmode_g->miscreg);
518 u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
520 crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
522 // Disable CRTC write protection
523 outw(0x0011, crtc_addr);
525 regs = GET_GLOBAL(vmode_g->crtc_regs);
526 for (i = 0; i <= 0x18; i++) {
528 outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
531 // Set the misc register
532 outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
535 outb(0x20, VGAREG_ACTL_ADDRESS);
536 inb(VGAREG_ACTL_RESET);
540 /****************************************************************
542 ****************************************************************/
545 vgahw_enable_video_addressing(u8 disable)
547 u8 v = (disable & 1) ? 0x00 : 0x02;
548 u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
549 outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
555 // switch to color mode and enable CPU access 480 lines
556 outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
557 // more than 64k 3C4/04
558 outb(0x04, VGAREG_SEQU_ADDRESS);
559 outb(0x02, VGAREG_SEQU_DATA);