blob: 6998cd09268090a6b33e67c76264bbd935612573 [file] [log] [blame]
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001// VGA io port access
2//
3// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2001-2008 the LGPL VGABios developers Team
5//
6// This file may be distributed under the terms of the GNU LGPLv3 license.
7
Kevin O'Connor88ca7412011-12-31 04:24:20 -05008#include "stdvga.h" // stdvga_init
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04009#include "ioport.h" // outb
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040010#include "farptr.h" // SET_FARVAR
Kevin O'Connorc990f272011-12-31 16:00:54 -050011#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor2bec7d62011-12-31 04:31:16 -050012#include "util.h" // memcpy_far
Kevin O'Connor5108c692011-12-31 19:13:45 -050013#include "vbe.h" // VBE_RETURN_STATUS_FAILED
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040014
Kevin O'Connor414d0732009-05-31 22:42:04 -040015// TODO
16// * replace direct in/out calls with wrapper functions
17
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040018
19/****************************************************************
20 * Attribute control
21 ****************************************************************/
22
Kevin O'Connor821d6b42011-12-31 18:19:22 -050023static void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050024stdvga_screen_disable(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -040025{
26 inb(VGAREG_ACTL_RESET);
27 outb(0x00, VGAREG_ACTL_ADDRESS);
28}
29
Kevin O'Connor821d6b42011-12-31 18:19:22 -050030static void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050031stdvga_screen_enable(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -040032{
33 inb(VGAREG_ACTL_RESET);
34 outb(0x20, VGAREG_ACTL_ADDRESS);
35}
36
37void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050038stdvga_set_border_color(u8 color)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040039{
40 inb(VGAREG_ACTL_RESET);
41 outb(0x00, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040042 u8 v1 = color & 0x0f;
43 if (v1 & 0x08)
44 v1 += 0x08;
45 outb(v1, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040046
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040047 u8 v2 = color & 0x10;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040048 int i;
49 for (i = 1; i < 4; i++) {
50 outb(i, VGAREG_ACTL_ADDRESS);
51
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040052 u8 cur = inb(VGAREG_ACTL_READ_DATA);
53 cur &= 0xef;
54 cur |= v2;
55 outb(cur, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040056 }
57 outb(0x20, VGAREG_ACTL_ADDRESS);
58}
59
60void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050061stdvga_set_overscan_border_color(u8 color)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040062{
63 inb(VGAREG_ACTL_RESET);
64 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040065 outb(color, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040066 outb(0x20, VGAREG_ACTL_ADDRESS);
67}
68
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040069u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -050070stdvga_get_overscan_border_color(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040071{
72 inb(VGAREG_ACTL_RESET);
73 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040074 u8 v = inb(VGAREG_ACTL_READ_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040075 inb(VGAREG_ACTL_RESET);
76 outb(0x20, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040077 return v;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040078}
79
80void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050081stdvga_set_palette(u8 palid)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040082{
83 inb(VGAREG_ACTL_RESET);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040084 palid &= 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040085 int i;
86 for (i = 1; i < 4; i++) {
87 outb(i, VGAREG_ACTL_ADDRESS);
88
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040089 u8 v = inb(VGAREG_ACTL_READ_DATA);
90 v &= 0xfe;
91 v |= palid;
92 outb(v, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040093 }
94 outb(0x20, VGAREG_ACTL_ADDRESS);
95}
96
97void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050098stdvga_set_single_palette_reg(u8 reg, u8 val)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040099{
100 inb(VGAREG_ACTL_RESET);
101 outb(reg, VGAREG_ACTL_ADDRESS);
102 outb(val, VGAREG_ACTL_WRITE_DATA);
103 outb(0x20, VGAREG_ACTL_ADDRESS);
104}
105
106u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500107stdvga_get_single_palette_reg(u8 reg)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400108{
109 inb(VGAREG_ACTL_RESET);
110 outb(reg, VGAREG_ACTL_ADDRESS);
111 u8 v = inb(VGAREG_ACTL_READ_DATA);
112 inb(VGAREG_ACTL_RESET);
113 outb(0x20, VGAREG_ACTL_ADDRESS);
114 return v;
115}
116
117void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500118stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400119{
120 inb(VGAREG_ACTL_RESET);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400121 int i;
122 for (i = 0; i < 0x10; i++) {
123 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400124 u8 val = GET_FARVAR(seg, *data_far);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400125 outb(val, VGAREG_ACTL_WRITE_DATA);
126 data_far++;
127 }
128 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400129 outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400130 outb(0x20, VGAREG_ACTL_ADDRESS);
131}
132
133void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500134stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400135{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400136 int i;
137 for (i = 0; i < 0x10; i++) {
138 inb(VGAREG_ACTL_RESET);
139 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400140 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400141 data_far++;
142 }
143 inb(VGAREG_ACTL_RESET);
144 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400145 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400146 inb(VGAREG_ACTL_RESET);
147 outb(0x20, VGAREG_ACTL_ADDRESS);
148}
149
150void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500151stdvga_toggle_intensity(u8 flag)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400152{
153 inb(VGAREG_ACTL_RESET);
154 outb(0x10, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400155 u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400156 outb(val, VGAREG_ACTL_WRITE_DATA);
157 outb(0x20, VGAREG_ACTL_ADDRESS);
158}
159
160void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500161stdvga_select_video_dac_color_page(u8 flag, u8 data)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400162{
163 inb(VGAREG_ACTL_RESET);
164 outb(0x10, VGAREG_ACTL_ADDRESS);
165 u8 val = inb(VGAREG_ACTL_READ_DATA);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400166 if (!(flag & 0x01)) {
167 // select paging mode
168 val = (val & 0x7f) | (data << 7);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400169 outb(val, VGAREG_ACTL_WRITE_DATA);
170 outb(0x20, VGAREG_ACTL_ADDRESS);
171 return;
172 }
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400173 // select page
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400174 inb(VGAREG_ACTL_RESET);
175 outb(0x14, VGAREG_ACTL_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400176 if (!(val & 0x80))
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400177 data <<= 2;
178 data &= 0x0f;
179 outb(data, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400180 outb(0x20, VGAREG_ACTL_ADDRESS);
181}
182
183void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500184stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400185{
186 inb(VGAREG_ACTL_RESET);
187 outb(0x10, VGAREG_ACTL_ADDRESS);
188 u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
189
190 inb(VGAREG_ACTL_RESET);
191 outb(0x14, VGAREG_ACTL_ADDRESS);
192 u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
193 if (!(val1 & 0x01))
194 val2 >>= 2;
195
196 inb(VGAREG_ACTL_RESET);
197 outb(0x20, VGAREG_ACTL_ADDRESS);
198
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400199 *pmode = val1;
200 *curpage = val2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400201}
202
203
204/****************************************************************
205 * DAC control
206 ****************************************************************/
207
208void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500209stdvga_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400210{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400211 outb(start, VGAREG_DAC_WRITE_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400212 while (count) {
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400213 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400214 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400215 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400216 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400217 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400218 data_far++;
219 count--;
220 }
221}
222
223void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500224stdvga_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400225{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400226 outb(start, VGAREG_DAC_READ_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400227 while (count) {
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400228 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400229 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400230 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400231 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400232 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400233 data_far++;
234 count--;
235 }
236}
237
238void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500239stdvga_set_pel_mask(u8 val)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400240{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400241 outb(val, VGAREG_PEL_MASK);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400242}
243
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400244u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500245stdvga_get_pel_mask(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400246{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400247 return inb(VGAREG_PEL_MASK);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400248}
249
Kevin O'Connorca668642009-05-21 23:06:08 -0400250void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500251stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400252{
253 /* XXX: check this */
254 SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
255 SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
256 SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500257 stdvga_get_dac_regs(seg, info->dac, 0, 256);
Kevin O'Connorca668642009-05-21 23:06:08 -0400258 SET_FARVAR(seg, info->color_select, 0);
259}
260
261void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500262stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400263{
264 outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500265 stdvga_set_dac_regs(seg, info->dac, 0, 256);
Kevin O'Connorca668642009-05-21 23:06:08 -0400266 outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
267}
268
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500269void
270stdvga_perform_gray_scale_summing(u16 start, u16 count)
271{
272 stdvga_screen_disable();
273 int i;
274 for (i = start; i < start+count; i++) {
275 u8 rgb[3];
276 stdvga_get_dac_regs(GET_SEG(SS), rgb, i, 1);
277
278 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
279 u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
280 if (intensity > 0x3f)
281 intensity = 0x3f;
282
283 stdvga_set_dac_regs(GET_SEG(SS), rgb, i, 1);
284 }
285 stdvga_screen_enable();
286}
287
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400288
289/****************************************************************
290 * Memory control
291 ****************************************************************/
292
293void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500294stdvga_sequ_write(u8 index, u8 value)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400295{
296 outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
297}
298
299void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500300stdvga_grdc_write(u8 index, u8 value)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400301{
302 outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
303}
304
305void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500306stdvga_set_text_block_specifier(u8 spec)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400307{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400308 outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400309}
310
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500311
312/****************************************************************
313 * Font loading
314 ****************************************************************/
315
316static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500317get_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400318{
319 outw(0x0100, VGAREG_SEQU_ADDRESS);
320 outw(0x0402, VGAREG_SEQU_ADDRESS);
321 outw(0x0704, VGAREG_SEQU_ADDRESS);
322 outw(0x0300, VGAREG_SEQU_ADDRESS);
323 outw(0x0204, VGAREG_GRDC_ADDRESS);
324 outw(0x0005, VGAREG_GRDC_ADDRESS);
325 outw(0x0406, VGAREG_GRDC_ADDRESS);
326}
327
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500328static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500329release_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400330{
331 outw(0x0100, VGAREG_SEQU_ADDRESS);
332 outw(0x0302, VGAREG_SEQU_ADDRESS);
333 outw(0x0304, VGAREG_SEQU_ADDRESS);
334 outw(0x0300, VGAREG_SEQU_ADDRESS);
Kevin O'Connor7e1d5302011-12-31 15:52:22 -0500335 u16 v = (inb(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400336 outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
337 outw(0x0004, VGAREG_GRDC_ADDRESS);
338 outw(0x1005, VGAREG_GRDC_ADDRESS);
339}
340
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500341void
342stdvga_load_font(u16 seg, void *src_far, u16 count
343 , u16 start, u8 destflags, u8 fontsize)
344{
345 get_font_access();
346 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
347 void *dest_far = (void*)(blockaddr + start*32);
348 u16 i;
349 for (i = 0; i < count; i++)
350 memcpy_far(SEG_GRAPH, dest_far + i*32
351 , seg, src_far + i*fontsize, fontsize);
352 release_font_access();
353}
354
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400355
356/****************************************************************
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400357 * CRTC registers
358 ****************************************************************/
359
Kevin O'Connorc990f272011-12-31 16:00:54 -0500360u16
361stdvga_get_crtc(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400362{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500363 if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
364 return VGAREG_VGA_CRTC_ADDRESS;
365 return VGAREG_MDA_CRTC_ADDRESS;
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400366}
367
368void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500369stdvga_set_cursor_shape(u8 start, u8 end)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400370{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500371 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400372 outb(0x0a, crtc_addr);
373 outb(start, crtc_addr + 1);
374 outb(0x0b, crtc_addr);
375 outb(end, crtc_addr + 1);
376}
377
378void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500379stdvga_set_active_page(u16 address)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400380{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500381 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400382 outb(0x0c, crtc_addr);
383 outb((address & 0xff00) >> 8, crtc_addr + 1);
384 outb(0x0d, crtc_addr);
385 outb(address & 0x00ff, crtc_addr + 1);
386}
387
388void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500389stdvga_set_cursor_pos(u16 address)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400390{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500391 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400392 outb(0x0e, crtc_addr);
393 outb((address & 0xff00) >> 8, crtc_addr + 1);
394 outb(0x0f, crtc_addr);
395 outb(address & 0x00ff, crtc_addr + 1);
396}
397
398void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500399stdvga_set_scan_lines(u8 lines)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400400{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500401 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400402 outb(0x09, crtc_addr);
403 u8 crtc_r9 = inb(crtc_addr + 1);
404 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
405 outb(crtc_r9, crtc_addr + 1);
406}
407
408// Get vertical display end
409u16
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500410stdvga_get_vde(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400411{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500412 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400413 outb(0x12, crtc_addr);
414 u16 vde = inb(crtc_addr + 1);
415 outb(0x07, crtc_addr);
416 u8 ovl = inb(crtc_addr + 1);
417 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
418 return vde;
419}
420
421
422/****************************************************************
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400423 * Save/Restore/Set state
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400424 ****************************************************************/
425
426void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500427stdvga_save_state(u16 seg, struct saveVideoHardware *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400428{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500429 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connorca668642009-05-21 23:06:08 -0400430 SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
431 SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
432 SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
433 inb(VGAREG_ACTL_RESET);
434 u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
435 SET_FARVAR(seg, info->actl_index, ar_index);
436 SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
437
438 u16 i;
439 for (i=0; i<4; i++) {
440 outb(i+1, VGAREG_SEQU_ADDRESS);
441 SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
442 }
443 outb(0, VGAREG_SEQU_ADDRESS);
444 SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
445
446 for (i=0; i<25; i++) {
447 outb(i, crtc_addr);
448 SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
449 }
450
451 for (i=0; i<20; i++) {
452 inb(VGAREG_ACTL_RESET);
453 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
454 SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
455 }
456 inb(VGAREG_ACTL_RESET);
457
458 for (i=0; i<9; i++) {
459 outb(i, VGAREG_GRDC_ADDRESS);
460 SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
461 }
462
463 SET_FARVAR(seg, info->crtc_addr, crtc_addr);
464
465 /* XXX: read plane latches */
466 for (i=0; i<4; i++)
467 SET_FARVAR(seg, info->plane_latch[i], 0);
468}
469
470void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500471stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400472{
473 // Reset Attribute Ctl flip-flop
474 inb(VGAREG_ACTL_RESET);
475
476 u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
477
478 u16 i;
479 for (i=0; i<4; i++) {
480 outb(i+1, VGAREG_SEQU_ADDRESS);
481 outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
482 }
483 outb(0, VGAREG_SEQU_ADDRESS);
484 outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
485
486 // Disable CRTC write protection
487 outw(0x0011, crtc_addr);
488 // Set CRTC regs
489 for (i=0; i<25; i++)
490 if (i != 0x11) {
491 outb(i, crtc_addr);
492 outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
493 }
494 // select crtc base address
495 u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
496 if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
497 v |= 0x01;
498 outb(v, VGAREG_WRITE_MISC_OUTPUT);
499
500 // enable write protection if needed
501 outb(0x11, crtc_addr);
502 outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
503
504 // Set Attribute Ctl
505 u16 ar_index = GET_FARVAR(seg, info->actl_index);
506 inb(VGAREG_ACTL_RESET);
507 for (i=0; i<20; i++) {
508 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
509 outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
510 }
511 outb(ar_index, VGAREG_ACTL_ADDRESS);
512 inb(VGAREG_ACTL_RESET);
513
514 for (i=0; i<9; i++) {
515 outb(i, VGAREG_GRDC_ADDRESS);
516 outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
517 }
518
519 outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
520 outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
521 outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
522 outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
523}
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400524
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500525static void
526clear_screen(struct vgamode_s *vmode_g)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400527{
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500528 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500529 case MM_TEXT:
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500530 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
531 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500532 case MM_CGA:
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500533 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
534 break;
535 default:
536 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
537 // but it should always be 0xf anyway.
538 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
539 }
540}
541
Kevin O'Connor5108c692011-12-31 19:13:45 -0500542int
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500543stdvga_set_mode(int mode, int flags)
544{
545 // find the entry in the video modes
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500546 struct vgamode_s *vmode_g = stdvga_find_mode(mode);
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500547 dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
548 if (!vmode_g)
Kevin O'Connor5108c692011-12-31 19:13:45 -0500549 return VBE_RETURN_STATUS_FAILED;
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500550 struct stdvga_mode_s *stdmode_g = container_of(
551 vmode_g, struct stdvga_mode_s, info);
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500552
553 // if palette loading (bit 3 of modeset ctl = 0)
554 if (!(flags & MF_NOPALETTE)) { // Set the PEL mask
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500555 stdvga_set_pel_mask(GET_GLOBAL(stdmode_g->pelmask));
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500556
557 // From which palette
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500558 u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
559 u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500560
561 // Always 256*3 values
562 stdvga_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
563 u16 i;
564 for (i = palsize; i < 0x0100; i++) {
565 static u8 rgb[3] VAR16;
566 stdvga_set_dac_regs(get_global_seg(), rgb, i, 1);
567 }
568
569 if (flags & MF_GRAYSUM)
570 stdvga_perform_gray_scale_summing(0x00, 0x100);
571 }
572
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400573 // Reset Attribute Ctl flip-flop
574 inb(VGAREG_ACTL_RESET);
575
576 // Set Attribute Ctl
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500577 u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400578 u16 i;
579 for (i = 0; i <= 0x13; i++) {
580 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500581 outb(GET_GLOBAL(regs[i]), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400582 }
583 outb(0x14, VGAREG_ACTL_ADDRESS);
584 outb(0x00, VGAREG_ACTL_WRITE_DATA);
585
586 // Set Sequencer Ctl
587 outb(0, VGAREG_SEQU_ADDRESS);
588 outb(0x03, VGAREG_SEQU_DATA);
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500589 regs = GET_GLOBAL(stdmode_g->sequ_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400590 for (i = 1; i <= 4; i++) {
591 outb(i, VGAREG_SEQU_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500592 outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400593 }
594
595 // Set Grafx Ctl
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500596 regs = GET_GLOBAL(stdmode_g->grdc_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400597 for (i = 0; i <= 8; i++) {
598 outb(i, VGAREG_GRDC_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500599 outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400600 }
601
602 // Set CRTC address VGA or MDA
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500603 u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400604 u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
605 if (!(miscreg & 1))
606 crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
607
608 // Disable CRTC write protection
609 outw(0x0011, crtc_addr);
610 // Set CRTC regs
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500611 regs = GET_GLOBAL(stdmode_g->crtc_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400612 for (i = 0; i <= 0x18; i++) {
613 outb(i, crtc_addr);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500614 outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400615 }
616
617 // Set the misc register
618 outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
619
620 // Enable video
621 outb(0x20, VGAREG_ACTL_ADDRESS);
622 inb(VGAREG_ACTL_RESET);
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500623
624 // Clear screen
625 if (!(flags & MF_NOCLEARMEM))
626 clear_screen(vmode_g);
627
628 // Write the fonts in memory
629 u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500630 if (memmodel == MM_TEXT)
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500631 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
632
633 // Setup BDA variables
634 modeswitch_set_bda(mode, flags, vmode_g);
Kevin O'Connor5108c692011-12-31 19:13:45 -0500635
636 return 0;
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400637}
638
639
640/****************************************************************
641 * Misc
642 ****************************************************************/
643
644void
Kevin O'Connor34203cd2012-01-09 20:55:31 -0500645stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
646{
647 SET_FARVAR(seg, *dest, 0xffff);
648}
649
650void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500651stdvga_enable_video_addressing(u8 disable)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400652{
653 u8 v = (disable & 1) ? 0x00 : 0x02;
654 u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
655 outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
656}
657
Kevin O'Connor161d2012011-12-31 19:42:21 -0500658int
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500659stdvga_init(void)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400660{
661 // switch to color mode and enable CPU access 480 lines
662 outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
663 // more than 64k 3C4/04
664 outb(0x04, VGAREG_SEQU_ADDRESS);
665 outb(0x02, VGAREG_SEQU_DATA);
Kevin O'Connor161d2012011-12-31 19:42:21 -0500666
667 return 0;
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400668}