blob: c7331e45b42ea342c521622d5d213345b80d3dfc [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'Connor821d6b42011-12-31 18:19:22 -050014#include "vgabios.h" // find_vga_entry
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040015
Kevin O'Connor414d0732009-05-31 22:42:04 -040016// TODO
17// * replace direct in/out calls with wrapper functions
18
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040019
20/****************************************************************
21 * Attribute control
22 ****************************************************************/
23
Kevin O'Connor821d6b42011-12-31 18:19:22 -050024static void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050025stdvga_screen_disable(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -040026{
27 inb(VGAREG_ACTL_RESET);
28 outb(0x00, VGAREG_ACTL_ADDRESS);
29}
30
Kevin O'Connor821d6b42011-12-31 18:19:22 -050031static void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050032stdvga_screen_enable(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -040033{
34 inb(VGAREG_ACTL_RESET);
35 outb(0x20, VGAREG_ACTL_ADDRESS);
36}
37
38void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050039stdvga_set_border_color(u8 color)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040040{
41 inb(VGAREG_ACTL_RESET);
42 outb(0x00, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040043 u8 v1 = color & 0x0f;
44 if (v1 & 0x08)
45 v1 += 0x08;
46 outb(v1, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040047
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040048 u8 v2 = color & 0x10;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040049 int i;
50 for (i = 1; i < 4; i++) {
51 outb(i, VGAREG_ACTL_ADDRESS);
52
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040053 u8 cur = inb(VGAREG_ACTL_READ_DATA);
54 cur &= 0xef;
55 cur |= v2;
56 outb(cur, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040057 }
58 outb(0x20, VGAREG_ACTL_ADDRESS);
59}
60
61void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050062stdvga_set_overscan_border_color(u8 color)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040063{
64 inb(VGAREG_ACTL_RESET);
65 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040066 outb(color, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040067 outb(0x20, VGAREG_ACTL_ADDRESS);
68}
69
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040070u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -050071stdvga_get_overscan_border_color(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040072{
73 inb(VGAREG_ACTL_RESET);
74 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040075 u8 v = inb(VGAREG_ACTL_READ_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040076 inb(VGAREG_ACTL_RESET);
77 outb(0x20, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040078 return v;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040079}
80
81void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050082stdvga_set_palette(u8 palid)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040083{
84 inb(VGAREG_ACTL_RESET);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040085 palid &= 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040086 int i;
87 for (i = 1; i < 4; i++) {
88 outb(i, VGAREG_ACTL_ADDRESS);
89
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040090 u8 v = inb(VGAREG_ACTL_READ_DATA);
91 v &= 0xfe;
92 v |= palid;
93 outb(v, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040094 }
95 outb(0x20, VGAREG_ACTL_ADDRESS);
96}
97
98void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050099stdvga_set_single_palette_reg(u8 reg, u8 val)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400100{
101 inb(VGAREG_ACTL_RESET);
102 outb(reg, VGAREG_ACTL_ADDRESS);
103 outb(val, VGAREG_ACTL_WRITE_DATA);
104 outb(0x20, VGAREG_ACTL_ADDRESS);
105}
106
107u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500108stdvga_get_single_palette_reg(u8 reg)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400109{
110 inb(VGAREG_ACTL_RESET);
111 outb(reg, VGAREG_ACTL_ADDRESS);
112 u8 v = inb(VGAREG_ACTL_READ_DATA);
113 inb(VGAREG_ACTL_RESET);
114 outb(0x20, VGAREG_ACTL_ADDRESS);
115 return v;
116}
117
118void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500119stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400120{
121 inb(VGAREG_ACTL_RESET);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400122 int i;
123 for (i = 0; i < 0x10; i++) {
124 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400125 u8 val = GET_FARVAR(seg, *data_far);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400126 outb(val, VGAREG_ACTL_WRITE_DATA);
127 data_far++;
128 }
129 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400130 outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400131 outb(0x20, VGAREG_ACTL_ADDRESS);
132}
133
134void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500135stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400136{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400137 int i;
138 for (i = 0; i < 0x10; i++) {
139 inb(VGAREG_ACTL_RESET);
140 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400141 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400142 data_far++;
143 }
144 inb(VGAREG_ACTL_RESET);
145 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400146 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400147 inb(VGAREG_ACTL_RESET);
148 outb(0x20, VGAREG_ACTL_ADDRESS);
149}
150
151void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500152stdvga_toggle_intensity(u8 flag)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400153{
154 inb(VGAREG_ACTL_RESET);
155 outb(0x10, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400156 u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400157 outb(val, VGAREG_ACTL_WRITE_DATA);
158 outb(0x20, VGAREG_ACTL_ADDRESS);
159}
160
161void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500162stdvga_select_video_dac_color_page(u8 flag, u8 data)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400163{
164 inb(VGAREG_ACTL_RESET);
165 outb(0x10, VGAREG_ACTL_ADDRESS);
166 u8 val = inb(VGAREG_ACTL_READ_DATA);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400167 if (!(flag & 0x01)) {
168 // select paging mode
169 val = (val & 0x7f) | (data << 7);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400170 outb(val, VGAREG_ACTL_WRITE_DATA);
171 outb(0x20, VGAREG_ACTL_ADDRESS);
172 return;
173 }
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400174 // select page
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400175 inb(VGAREG_ACTL_RESET);
176 outb(0x14, VGAREG_ACTL_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400177 if (!(val & 0x80))
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400178 data <<= 2;
179 data &= 0x0f;
180 outb(data, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400181 outb(0x20, VGAREG_ACTL_ADDRESS);
182}
183
184void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500185stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400186{
187 inb(VGAREG_ACTL_RESET);
188 outb(0x10, VGAREG_ACTL_ADDRESS);
189 u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
190
191 inb(VGAREG_ACTL_RESET);
192 outb(0x14, VGAREG_ACTL_ADDRESS);
193 u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
194 if (!(val1 & 0x01))
195 val2 >>= 2;
196
197 inb(VGAREG_ACTL_RESET);
198 outb(0x20, VGAREG_ACTL_ADDRESS);
199
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400200 *pmode = val1;
201 *curpage = val2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400202}
203
204
205/****************************************************************
206 * DAC control
207 ****************************************************************/
208
209void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500210stdvga_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400211{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400212 outb(start, VGAREG_DAC_WRITE_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400213 while (count) {
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400214 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400215 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400216 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400217 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400218 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400219 data_far++;
220 count--;
221 }
222}
223
224void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500225stdvga_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400226{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400227 outb(start, VGAREG_DAC_READ_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400228 while (count) {
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400229 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400230 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400231 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400232 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400233 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400234 data_far++;
235 count--;
236 }
237}
238
239void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500240stdvga_set_pel_mask(u8 val)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400241{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400242 outb(val, VGAREG_PEL_MASK);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400243}
244
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400245u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500246stdvga_get_pel_mask(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400247{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400248 return inb(VGAREG_PEL_MASK);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400249}
250
Kevin O'Connorca668642009-05-21 23:06:08 -0400251void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500252stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400253{
254 /* XXX: check this */
255 SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
256 SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
257 SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500258 stdvga_get_dac_regs(seg, info->dac, 0, 256);
Kevin O'Connorca668642009-05-21 23:06:08 -0400259 SET_FARVAR(seg, info->color_select, 0);
260}
261
262void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500263stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400264{
265 outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500266 stdvga_set_dac_regs(seg, info->dac, 0, 256);
Kevin O'Connorca668642009-05-21 23:06:08 -0400267 outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
268}
269
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500270void
271stdvga_perform_gray_scale_summing(u16 start, u16 count)
272{
273 stdvga_screen_disable();
274 int i;
275 for (i = start; i < start+count; i++) {
276 u8 rgb[3];
277 stdvga_get_dac_regs(GET_SEG(SS), rgb, i, 1);
278
279 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
280 u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
281 if (intensity > 0x3f)
282 intensity = 0x3f;
283
284 stdvga_set_dac_regs(GET_SEG(SS), rgb, i, 1);
285 }
286 stdvga_screen_enable();
287}
288
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400289
290/****************************************************************
291 * Memory control
292 ****************************************************************/
293
294void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500295stdvga_sequ_write(u8 index, u8 value)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400296{
297 outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
298}
299
300void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500301stdvga_grdc_write(u8 index, u8 value)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400302{
303 outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
304}
305
306void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500307stdvga_set_text_block_specifier(u8 spec)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400308{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400309 outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400310}
311
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500312
313/****************************************************************
314 * Font loading
315 ****************************************************************/
316
317static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500318get_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400319{
320 outw(0x0100, VGAREG_SEQU_ADDRESS);
321 outw(0x0402, VGAREG_SEQU_ADDRESS);
322 outw(0x0704, VGAREG_SEQU_ADDRESS);
323 outw(0x0300, VGAREG_SEQU_ADDRESS);
324 outw(0x0204, VGAREG_GRDC_ADDRESS);
325 outw(0x0005, VGAREG_GRDC_ADDRESS);
326 outw(0x0406, VGAREG_GRDC_ADDRESS);
327}
328
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500329static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500330release_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400331{
332 outw(0x0100, VGAREG_SEQU_ADDRESS);
333 outw(0x0302, VGAREG_SEQU_ADDRESS);
334 outw(0x0304, VGAREG_SEQU_ADDRESS);
335 outw(0x0300, VGAREG_SEQU_ADDRESS);
Kevin O'Connor7e1d5302011-12-31 15:52:22 -0500336 u16 v = (inb(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400337 outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
338 outw(0x0004, VGAREG_GRDC_ADDRESS);
339 outw(0x1005, VGAREG_GRDC_ADDRESS);
340}
341
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500342void
343stdvga_load_font(u16 seg, void *src_far, u16 count
344 , u16 start, u8 destflags, u8 fontsize)
345{
346 get_font_access();
347 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
348 void *dest_far = (void*)(blockaddr + start*32);
349 u16 i;
350 for (i = 0; i < count; i++)
351 memcpy_far(SEG_GRAPH, dest_far + i*32
352 , seg, src_far + i*fontsize, fontsize);
353 release_font_access();
354}
355
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400356
357/****************************************************************
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400358 * CRTC registers
359 ****************************************************************/
360
Kevin O'Connorc990f272011-12-31 16:00:54 -0500361u16
362stdvga_get_crtc(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400363{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500364 if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
365 return VGAREG_VGA_CRTC_ADDRESS;
366 return VGAREG_MDA_CRTC_ADDRESS;
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400367}
368
369void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500370stdvga_set_cursor_shape(u8 start, u8 end)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400371{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500372 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400373 outb(0x0a, crtc_addr);
374 outb(start, crtc_addr + 1);
375 outb(0x0b, crtc_addr);
376 outb(end, crtc_addr + 1);
377}
378
379void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500380stdvga_set_active_page(u16 address)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400381{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500382 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400383 outb(0x0c, crtc_addr);
384 outb((address & 0xff00) >> 8, crtc_addr + 1);
385 outb(0x0d, crtc_addr);
386 outb(address & 0x00ff, crtc_addr + 1);
387}
388
389void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500390stdvga_set_cursor_pos(u16 address)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400391{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500392 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400393 outb(0x0e, crtc_addr);
394 outb((address & 0xff00) >> 8, crtc_addr + 1);
395 outb(0x0f, crtc_addr);
396 outb(address & 0x00ff, crtc_addr + 1);
397}
398
399void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500400stdvga_set_scan_lines(u8 lines)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400401{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500402 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400403 outb(0x09, crtc_addr);
404 u8 crtc_r9 = inb(crtc_addr + 1);
405 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
406 outb(crtc_r9, crtc_addr + 1);
407}
408
409// Get vertical display end
410u16
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500411stdvga_get_vde(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400412{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500413 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400414 outb(0x12, crtc_addr);
415 u16 vde = inb(crtc_addr + 1);
416 outb(0x07, crtc_addr);
417 u8 ovl = inb(crtc_addr + 1);
418 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
419 return vde;
420}
421
422
423/****************************************************************
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400424 * Save/Restore/Set state
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400425 ****************************************************************/
426
427void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500428stdvga_save_state(u16 seg, struct saveVideoHardware *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400429{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500430 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connorca668642009-05-21 23:06:08 -0400431 SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
432 SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
433 SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
434 inb(VGAREG_ACTL_RESET);
435 u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
436 SET_FARVAR(seg, info->actl_index, ar_index);
437 SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
438
439 u16 i;
440 for (i=0; i<4; i++) {
441 outb(i+1, VGAREG_SEQU_ADDRESS);
442 SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
443 }
444 outb(0, VGAREG_SEQU_ADDRESS);
445 SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
446
447 for (i=0; i<25; i++) {
448 outb(i, crtc_addr);
449 SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
450 }
451
452 for (i=0; i<20; i++) {
453 inb(VGAREG_ACTL_RESET);
454 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
455 SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
456 }
457 inb(VGAREG_ACTL_RESET);
458
459 for (i=0; i<9; i++) {
460 outb(i, VGAREG_GRDC_ADDRESS);
461 SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
462 }
463
464 SET_FARVAR(seg, info->crtc_addr, crtc_addr);
465
466 /* XXX: read plane latches */
467 for (i=0; i<4; i++)
468 SET_FARVAR(seg, info->plane_latch[i], 0);
469}
470
471void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500472stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400473{
474 // Reset Attribute Ctl flip-flop
475 inb(VGAREG_ACTL_RESET);
476
477 u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
478
479 u16 i;
480 for (i=0; i<4; i++) {
481 outb(i+1, VGAREG_SEQU_ADDRESS);
482 outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
483 }
484 outb(0, VGAREG_SEQU_ADDRESS);
485 outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
486
487 // Disable CRTC write protection
488 outw(0x0011, crtc_addr);
489 // Set CRTC regs
490 for (i=0; i<25; i++)
491 if (i != 0x11) {
492 outb(i, crtc_addr);
493 outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
494 }
495 // select crtc base address
496 u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
497 if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
498 v |= 0x01;
499 outb(v, VGAREG_WRITE_MISC_OUTPUT);
500
501 // enable write protection if needed
502 outb(0x11, crtc_addr);
503 outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
504
505 // Set Attribute Ctl
506 u16 ar_index = GET_FARVAR(seg, info->actl_index);
507 inb(VGAREG_ACTL_RESET);
508 for (i=0; i<20; i++) {
509 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
510 outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
511 }
512 outb(ar_index, VGAREG_ACTL_ADDRESS);
513 inb(VGAREG_ACTL_RESET);
514
515 for (i=0; i<9; i++) {
516 outb(i, VGAREG_GRDC_ADDRESS);
517 outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
518 }
519
520 outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
521 outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
522 outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
523 outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
524}
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400525
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500526static void
527clear_screen(struct vgamode_s *vmode_g)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400528{
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500529 switch (GET_GLOBAL(vmode_g->memmodel)) {
530 case CTEXT:
531 case MTEXT:
532 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
533 break;
534 case CGA:
535 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
536 break;
537 default:
538 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
539 // but it should always be 0xf anyway.
540 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
541 }
542}
543
Kevin O'Connor5108c692011-12-31 19:13:45 -0500544int
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500545stdvga_set_mode(int mode, int flags)
546{
547 // find the entry in the video modes
548 struct vgamode_s *vmode_g = find_vga_entry(mode);
549 dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
550 if (!vmode_g)
Kevin O'Connor5108c692011-12-31 19:13:45 -0500551 return VBE_RETURN_STATUS_FAILED;
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
555 stdvga_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
556
557 // From which palette
558 u8 *palette_g = GET_GLOBAL(vmode_g->dac);
559 u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
560
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'Connor87233e92011-12-23 21:40:34 -0500577 u8 *regs = GET_GLOBAL(vmode_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'Connor87233e92011-12-23 21:40:34 -0500589 regs = GET_GLOBAL(vmode_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'Connor87233e92011-12-23 21:40:34 -0500596 regs = GET_GLOBAL(vmode_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'Connor87233e92011-12-23 21:40:34 -0500603 u8 miscreg = GET_GLOBAL(vmode_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'Connor87233e92011-12-23 21:40:34 -0500611 regs = GET_GLOBAL(vmode_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);
630 if (memmodel & TEXT)
631 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'Connor88ca7412011-12-31 04:24:20 -0500645stdvga_enable_video_addressing(u8 disable)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400646{
647 u8 v = (disable & 1) ? 0x00 : 0x02;
648 u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
649 outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
650}
651
Kevin O'Connor161d2012011-12-31 19:42:21 -0500652int
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500653stdvga_init(void)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400654{
655 // switch to color mode and enable CPU access 480 lines
656 outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
657 // more than 64k 3C4/04
658 outb(0x04, VGAREG_SEQU_ADDRESS);
659 outb(0x02, VGAREG_SEQU_DATA);
Kevin O'Connor161d2012011-12-31 19:42:21 -0500660
661 return 0;
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400662}