b7def3290be23ee93b2a4eee8391f362afe1a35a
[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
274 /****************************************************************
275  * Save/Restore/Set state
276  ****************************************************************/
277
278 void
279 stdvga_save_state(u16 seg, struct saveVideoHardware *info)
280 {
281     u16 crtc_addr = stdvga_get_crtc();
282     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
283     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
284     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
285     SET_FARVAR(seg, info->actl_index, stdvga_attrindex_read());
286     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
287
288     int i;
289     for (i=0; i<4; i++)
290         SET_FARVAR(seg, info->sequ_regs[i], stdvga_sequ_read(i+1));
291     SET_FARVAR(seg, info->sequ0, stdvga_sequ_read(0));
292
293     for (i=0; i<25; i++)
294         SET_FARVAR(seg, info->crtc_regs[i], stdvga_crtc_read(crtc_addr, i));
295
296     for (i=0; i<20; i++)
297         SET_FARVAR(seg, info->actl_regs[i], stdvga_attr_read(i));
298
299     for (i=0; i<9; i++)
300         SET_FARVAR(seg, info->grdc_regs[i], stdvga_grdc_read(i));
301
302     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
303
304     /* XXX: read plane latches */
305     for (i=0; i<4; i++)
306         SET_FARVAR(seg, info->plane_latch[i], 0);
307 }
308
309 void
310 stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
311 {
312     int i;
313     for (i=0; i<4; i++)
314         stdvga_sequ_write(i+1, GET_FARVAR(seg, info->sequ_regs[i]));
315     stdvga_sequ_write(0x00, GET_FARVAR(seg, info->sequ0));
316
317     // Disable CRTC write protection
318     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
319     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
320     // Set CRTC regs
321     for (i=0; i<25; i++)
322         if (i != 0x11)
323             stdvga_crtc_write(crtc_addr, i, GET_FARVAR(seg, info->crtc_regs[i]));
324     // select crtc base address
325     stdvga_misc_mask(0x01, crtc_addr == VGAREG_VGA_CRTC_ADDRESS ? 0x01 : 0x00);
326
327     // enable write protection if needed
328     stdvga_crtc_write(crtc_addr, 0x11, GET_FARVAR(seg, info->crtc_regs[0x11]));
329
330     // Set Attribute Ctl
331     for (i=0; i<20; i++)
332         stdvga_attr_write(i, GET_FARVAR(seg, info->actl_regs[i]));
333     stdvga_attrindex_write(GET_FARVAR(seg, info->actl_index));
334
335     for (i=0; i<9; i++)
336         stdvga_grdc_write(i, GET_FARVAR(seg, info->grdc_regs[i]));
337
338     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
339     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
340     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
341     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
342 }
343
344 static void
345 clear_screen(struct vgamode_s *vmode_g)
346 {
347     switch (GET_GLOBAL(vmode_g->memmodel)) {
348     case MM_TEXT:
349         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
350         break;
351     case MM_CGA:
352         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
353         break;
354     default:
355         // XXX - old code gets/sets/restores sequ register 2 to 0xf -
356         // but it should always be 0xf anyway.
357         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
358     }
359 }
360
361 int
362 stdvga_set_mode(struct vgamode_s *vmode_g, int flags)
363 {
364     if (! stdvga_is_mode(vmode_g)) {
365         warn_internalerror();
366         return -1;
367     }
368     struct stdvga_mode_s *stdmode_g = container_of(
369         vmode_g, struct stdvga_mode_s, info);
370
371     // if palette loading (bit 3 of modeset ctl = 0)
372     if (!(flags & MF_NOPALETTE)) {    // Set the PEL mask
373         stdvga_pelmask_write(GET_GLOBAL(stdmode_g->pelmask));
374
375         // From which palette
376         u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
377         u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
378
379         // Always 256*3 values
380         stdvga_dac_write(get_global_seg(), palette_g, 0, palsize);
381         int i;
382         for (i = palsize; i < 0x0100; i++) {
383             static u8 rgb[3] VAR16;
384             stdvga_dac_write(get_global_seg(), rgb, i, 1);
385         }
386
387         if (flags & MF_GRAYSUM)
388             stdvga_perform_gray_scale_summing(0x00, 0x100);
389     }
390
391     // Set Attribute Ctl
392     u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
393     int i;
394     for (i = 0; i <= 0x13; i++)
395         stdvga_attr_write(i, GET_GLOBAL(regs[i]));
396     stdvga_attr_write(0x14, 0x00);
397
398     // Set Sequencer Ctl
399     stdvga_sequ_write(0x00, 0x03);
400     regs = GET_GLOBAL(stdmode_g->sequ_regs);
401     for (i = 1; i <= 4; i++)
402         stdvga_sequ_write(i, GET_GLOBAL(regs[i - 1]));
403
404     // Set Grafx Ctl
405     regs = GET_GLOBAL(stdmode_g->grdc_regs);
406     for (i = 0; i <= 8; i++)
407         stdvga_grdc_write(i, GET_GLOBAL(regs[i]));
408
409     // Set CRTC address VGA or MDA
410     u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
411     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
412     if (!(miscreg & 1))
413         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
414
415     // Disable CRTC write protection
416     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
417     // Set CRTC regs
418     regs = GET_GLOBAL(stdmode_g->crtc_regs);
419     for (i = 0; i <= 0x18; i++)
420         stdvga_crtc_write(crtc_addr, i, GET_GLOBAL(regs[i]));
421
422     // Set the misc register
423     stdvga_misc_write(miscreg);
424
425     // Enable video
426     stdvga_attrindex_write(0x20);
427
428     // Clear screen
429     if (!(flags & MF_NOCLEARMEM))
430         clear_screen(vmode_g);
431
432     // Write the fonts in memory
433     u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
434     if (memmodel == MM_TEXT)
435         stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
436
437     return 0;
438 }
439
440
441 /****************************************************************
442  * Misc
443  ****************************************************************/
444
445 void
446 stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
447 {
448     SET_FARVAR(seg, *dest, 0xffff);
449 }
450
451 void
452 stdvga_enable_video_addressing(u8 disable)
453 {
454     u8 v = (disable & 1) ? 0x00 : 0x02;
455     stdvga_misc_mask(0x02, v);
456 }
457
458 int
459 stdvga_init(void)
460 {
461     // switch to color mode and enable CPU access 480 lines
462     stdvga_misc_write(0xc3);
463     // more than 64k 3C4/04
464     stdvga_sequ_write(0x04, 0x02);
465
466     return 0;
467 }