vgabios: Add support for vesa get/set window function.
[seabios.git] / vgasrc / stdvga.c
1 // Standard VGA driver code
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
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
14
15 /****************************************************************
16  * Attribute control
17  ****************************************************************/
18
19 void
20 stdvga_set_border_color(u8 color)
21 {
22     u8 v1 = color & 0x0f;
23     if (v1 & 0x08)
24         v1 += 0x08;
25     stdvga_attr_write(0x00, v1);
26
27     int i;
28     for (i = 1; i < 4; i++)
29         stdvga_attr_mask(i, 0x10, color & 0x10);
30 }
31
32 void
33 stdvga_set_overscan_border_color(u8 color)
34 {
35     stdvga_attr_write(0x11, color);
36 }
37
38 u8
39 stdvga_get_overscan_border_color(void)
40 {
41     return stdvga_attr_read(0x11);
42 }
43
44 void
45 stdvga_set_palette(u8 palid)
46 {
47     int i;
48     for (i = 1; i < 4; i++)
49         stdvga_attr_mask(i, 0x01, palid & 0x01);
50 }
51
52 void
53 stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
54 {
55     int i;
56     for (i = 0; i < 0x10; i++) {
57         stdvga_attr_write(i, GET_FARVAR(seg, *data_far));
58         data_far++;
59     }
60     stdvga_attr_write(0x11, GET_FARVAR(seg, *data_far));
61 }
62
63 void
64 stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
65 {
66     int i;
67     for (i = 0; i < 0x10; i++) {
68         SET_FARVAR(seg, *data_far, stdvga_attr_read(i));
69         data_far++;
70     }
71     SET_FARVAR(seg, *data_far, stdvga_attr_read(0x11));
72 }
73
74 void
75 stdvga_toggle_intensity(u8 flag)
76 {
77     stdvga_attr_mask(0x10, 0x08, (flag & 0x01) << 3);
78 }
79
80 void
81 stdvga_select_video_dac_color_page(u8 flag, u8 data)
82 {
83     if (!(flag & 0x01)) {
84         // select paging mode
85         stdvga_attr_mask(0x10, 0x80, data << 7);
86         return;
87     }
88     // select page
89     u8 val = stdvga_attr_read(0x10);
90     if (!(val & 0x80))
91         data <<= 2;
92     data &= 0x0f;
93     stdvga_attr_write(0x14, data);
94 }
95
96 void
97 stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
98 {
99     u8 val1 = stdvga_attr_read(0x10) >> 7;
100     u8 val2 = stdvga_attr_read(0x14) & 0x0f;
101     if (!(val1 & 0x01))
102         val2 >>= 2;
103     *pmode = val1;
104     *curpage = val2;
105 }
106
107
108 /****************************************************************
109  * DAC control
110  ****************************************************************/
111
112 void
113 stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
114 {
115     /* XXX: check this */
116     SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
117     SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
118     SET_FARVAR(seg, info->pelmask, stdvga_pelmask_read());
119     stdvga_dac_read(seg, info->dac, 0, 256);
120     SET_FARVAR(seg, info->color_select, 0);
121 }
122
123 void
124 stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
125 {
126     stdvga_pelmask_write(GET_FARVAR(seg, info->pelmask));
127     stdvga_dac_write(seg, info->dac, 0, 256);
128     outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
129 }
130
131 void
132 stdvga_perform_gray_scale_summing(u16 start, u16 count)
133 {
134     stdvga_attrindex_write(0x00);
135     int i;
136     for (i = start; i < start+count; i++) {
137         u8 rgb[3];
138         stdvga_dac_read(GET_SEG(SS), rgb, i, 1);
139
140         // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
141         u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
142         if (intensity > 0x3f)
143             intensity = 0x3f;
144
145         stdvga_dac_write(GET_SEG(SS), rgb, i, 1);
146     }
147     stdvga_attrindex_write(0x20);
148 }
149
150
151 /****************************************************************
152  * Memory control
153  ****************************************************************/
154
155 void
156 stdvga_set_text_block_specifier(u8 spec)
157 {
158     stdvga_sequ_write(0x03, spec);
159 }
160
161 // Enable reads and writes to the given "plane" when in planar4 mode.
162 void
163 stdvga_planar4_plane(int plane)
164 {
165     if (plane < 0) {
166         // Return to default mode (read plane0, write all planes)
167         stdvga_sequ_write(0x02, 0x0f);
168         stdvga_grdc_write(0x04, 0);
169     } else {
170         stdvga_sequ_write(0x02, 1<<plane);
171         stdvga_grdc_write(0x04, plane);
172     }
173 }
174
175
176 /****************************************************************
177  * Font loading
178  ****************************************************************/
179
180 static void
181 get_font_access(void)
182 {
183     stdvga_sequ_write(0x00, 0x01);
184     stdvga_sequ_write(0x02, 0x04);
185     stdvga_sequ_write(0x04, 0x07);
186     stdvga_sequ_write(0x00, 0x03);
187     stdvga_grdc_write(0x04, 0x02);
188     stdvga_grdc_write(0x05, 0x00);
189     stdvga_grdc_write(0x06, 0x04);
190 }
191
192 static void
193 release_font_access(void)
194 {
195     stdvga_sequ_write(0x00, 0x01);
196     stdvga_sequ_write(0x02, 0x03);
197     stdvga_sequ_write(0x04, 0x03);
198     stdvga_sequ_write(0x00, 0x03);
199     u16 v = (stdvga_misc_read() & 0x01) ? 0x0e : 0x0a;
200     stdvga_grdc_write(0x06, v);
201     stdvga_grdc_write(0x04, 0x00);
202     stdvga_grdc_write(0x05, 0x10);
203 }
204
205 void
206 stdvga_load_font(u16 seg, void *src_far, u16 count
207                  , u16 start, u8 destflags, u8 fontsize)
208 {
209     get_font_access();
210     u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
211     void *dest_far = (void*)(blockaddr + start*32);
212     u16 i;
213     for (i = 0; i < count; i++)
214         memcpy_far(SEG_GRAPH, dest_far + i*32
215                    , seg, src_far + i*fontsize, fontsize);
216     release_font_access();
217 }
218
219
220 /****************************************************************
221  * CRTC registers
222  ****************************************************************/
223
224 u16
225 stdvga_get_crtc(void)
226 {
227     if (stdvga_misc_read() & 1)
228         return VGAREG_VGA_CRTC_ADDRESS;
229     return VGAREG_MDA_CRTC_ADDRESS;
230 }
231
232 void
233 stdvga_set_cursor_shape(u8 start, u8 end)
234 {
235     u16 crtc_addr = stdvga_get_crtc();
236     stdvga_crtc_write(crtc_addr, 0x0a, start);
237     stdvga_crtc_write(crtc_addr, 0x0b, end);
238 }
239
240 void
241 stdvga_set_active_page(u16 address)
242 {
243     u16 crtc_addr = stdvga_get_crtc();
244     stdvga_crtc_write(crtc_addr, 0x0c, address >> 8);
245     stdvga_crtc_write(crtc_addr, 0x0d, address);
246 }
247
248 void
249 stdvga_set_cursor_pos(u16 address)
250 {
251     u16 crtc_addr = stdvga_get_crtc();
252     stdvga_crtc_write(crtc_addr, 0x0e, address >> 8);
253     stdvga_crtc_write(crtc_addr, 0x0f, address);
254 }
255
256 void
257 stdvga_set_scan_lines(u8 lines)
258 {
259     stdvga_crtc_mask(stdvga_get_crtc(), 0x09, 0x1f, lines - 1);
260 }
261
262 // Get vertical display end
263 u16
264 stdvga_get_vde(void)
265 {
266     u16 crtc_addr = stdvga_get_crtc();
267     u16 vde = stdvga_crtc_read(crtc_addr, 0x12);
268     u8 ovl = stdvga_crtc_read(crtc_addr, 0x07);
269     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
270     return vde;
271 }
272
273 int
274 stdvga_get_window(struct vgamode_s *vmode_g, int window)
275 {
276     return -1;
277 }
278
279 int
280 stdvga_set_window(struct vgamode_s *vmode_g, int window, int val)
281 {
282     return -1;
283 }
284
285
286 /****************************************************************
287  * Save/Restore/Set state
288  ****************************************************************/
289
290 void
291 stdvga_save_state(u16 seg, struct saveVideoHardware *info)
292 {
293     u16 crtc_addr = stdvga_get_crtc();
294     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
295     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
296     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
297     SET_FARVAR(seg, info->actl_index, stdvga_attrindex_read());
298     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
299
300     int i;
301     for (i=0; i<4; i++)
302         SET_FARVAR(seg, info->sequ_regs[i], stdvga_sequ_read(i+1));
303     SET_FARVAR(seg, info->sequ0, stdvga_sequ_read(0));
304
305     for (i=0; i<25; i++)
306         SET_FARVAR(seg, info->crtc_regs[i], stdvga_crtc_read(crtc_addr, i));
307
308     for (i=0; i<20; i++)
309         SET_FARVAR(seg, info->actl_regs[i], stdvga_attr_read(i));
310
311     for (i=0; i<9; i++)
312         SET_FARVAR(seg, info->grdc_regs[i], stdvga_grdc_read(i));
313
314     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
315
316     /* XXX: read plane latches */
317     for (i=0; i<4; i++)
318         SET_FARVAR(seg, info->plane_latch[i], 0);
319 }
320
321 void
322 stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
323 {
324     int i;
325     for (i=0; i<4; i++)
326         stdvga_sequ_write(i+1, GET_FARVAR(seg, info->sequ_regs[i]));
327     stdvga_sequ_write(0x00, GET_FARVAR(seg, info->sequ0));
328
329     // Disable CRTC write protection
330     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
331     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
332     // Set CRTC regs
333     for (i=0; i<25; i++)
334         if (i != 0x11)
335             stdvga_crtc_write(crtc_addr, i, GET_FARVAR(seg, info->crtc_regs[i]));
336     // select crtc base address
337     stdvga_misc_mask(0x01, crtc_addr == VGAREG_VGA_CRTC_ADDRESS ? 0x01 : 0x00);
338
339     // enable write protection if needed
340     stdvga_crtc_write(crtc_addr, 0x11, GET_FARVAR(seg, info->crtc_regs[0x11]));
341
342     // Set Attribute Ctl
343     for (i=0; i<20; i++)
344         stdvga_attr_write(i, GET_FARVAR(seg, info->actl_regs[i]));
345     stdvga_attrindex_write(GET_FARVAR(seg, info->actl_index));
346
347     for (i=0; i<9; i++)
348         stdvga_grdc_write(i, GET_FARVAR(seg, info->grdc_regs[i]));
349
350     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
351     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
352     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
353     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
354 }
355
356 static void
357 clear_screen(struct vgamode_s *vmode_g)
358 {
359     switch (GET_GLOBAL(vmode_g->memmodel)) {
360     case MM_TEXT:
361         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
362         break;
363     case MM_CGA:
364         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
365         break;
366     default:
367         // XXX - old code gets/sets/restores sequ register 2 to 0xf -
368         // but it should always be 0xf anyway.
369         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
370     }
371 }
372
373 int
374 stdvga_set_mode(struct vgamode_s *vmode_g, int flags)
375 {
376     if (! stdvga_is_mode(vmode_g)) {
377         warn_internalerror();
378         return -1;
379     }
380     struct stdvga_mode_s *stdmode_g = container_of(
381         vmode_g, struct stdvga_mode_s, info);
382
383     // if palette loading (bit 3 of modeset ctl = 0)
384     if (!(flags & MF_NOPALETTE)) {    // Set the PEL mask
385         stdvga_pelmask_write(GET_GLOBAL(stdmode_g->pelmask));
386
387         // From which palette
388         u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
389         u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
390
391         // Always 256*3 values
392         stdvga_dac_write(get_global_seg(), palette_g, 0, palsize);
393         int i;
394         for (i = palsize; i < 0x0100; i++) {
395             static u8 rgb[3] VAR16;
396             stdvga_dac_write(get_global_seg(), rgb, i, 1);
397         }
398
399         if (flags & MF_GRAYSUM)
400             stdvga_perform_gray_scale_summing(0x00, 0x100);
401     }
402
403     // Set Attribute Ctl
404     u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
405     int i;
406     for (i = 0; i <= 0x13; i++)
407         stdvga_attr_write(i, GET_GLOBAL(regs[i]));
408     stdvga_attr_write(0x14, 0x00);
409
410     // Set Sequencer Ctl
411     stdvga_sequ_write(0x00, 0x03);
412     regs = GET_GLOBAL(stdmode_g->sequ_regs);
413     for (i = 1; i <= 4; i++)
414         stdvga_sequ_write(i, GET_GLOBAL(regs[i - 1]));
415
416     // Set Grafx Ctl
417     regs = GET_GLOBAL(stdmode_g->grdc_regs);
418     for (i = 0; i <= 8; i++)
419         stdvga_grdc_write(i, GET_GLOBAL(regs[i]));
420
421     // Set CRTC address VGA or MDA
422     u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
423     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
424     if (!(miscreg & 1))
425         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
426
427     // Disable CRTC write protection
428     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
429     // Set CRTC regs
430     regs = GET_GLOBAL(stdmode_g->crtc_regs);
431     for (i = 0; i <= 0x18; i++)
432         stdvga_crtc_write(crtc_addr, i, GET_GLOBAL(regs[i]));
433
434     // Set the misc register
435     stdvga_misc_write(miscreg);
436
437     // Enable video
438     stdvga_attrindex_write(0x20);
439
440     // Clear screen
441     if (!(flags & MF_NOCLEARMEM))
442         clear_screen(vmode_g);
443
444     // Write the fonts in memory
445     u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
446     if (memmodel == MM_TEXT)
447         stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
448
449     return 0;
450 }
451
452
453 /****************************************************************
454  * Misc
455  ****************************************************************/
456
457 void
458 stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
459 {
460     SET_FARVAR(seg, *dest, 0xffff);
461 }
462
463 void
464 stdvga_enable_video_addressing(u8 disable)
465 {
466     u8 v = (disable & 1) ? 0x00 : 0x02;
467     stdvga_misc_mask(0x02, v);
468 }
469
470 int
471 stdvga_init(void)
472 {
473     // switch to color mode and enable CPU access 480 lines
474     stdvga_misc_write(0xc3);
475     // more than 64k 3C4/04
476     stdvga_sequ_write(0x04, 0x02);
477
478     return 0;
479 }