vgabios: Minor - pass display address to stdvga_set_cursor_pos().
[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 // Return the multiplication factor needed for the vga offset register.
233 int
234 stdvga_bpp_factor(struct vgamode_s *vmode_g)
235 {
236     switch (GET_GLOBAL(vmode_g->memmodel)) {
237     case MM_TEXT:
238         return 2;
239     case MM_CGA:
240         return GET_GLOBAL(vmode_g->depth);
241     case MM_PLANAR:
242         return 1;
243     default:
244         return 4;
245     }
246 }
247
248 void
249 stdvga_set_cursor_shape(u8 start, u8 end)
250 {
251     u16 crtc_addr = stdvga_get_crtc();
252     stdvga_crtc_write(crtc_addr, 0x0a, start);
253     stdvga_crtc_write(crtc_addr, 0x0b, end);
254 }
255
256 void
257 stdvga_set_cursor_pos(int address)
258 {
259     u16 crtc_addr = stdvga_get_crtc();
260     address /= 2;  // Assume we're in text mode.
261     stdvga_crtc_write(crtc_addr, 0x0e, address >> 8);
262     stdvga_crtc_write(crtc_addr, 0x0f, address);
263 }
264
265 void
266 stdvga_set_scan_lines(u8 lines)
267 {
268     stdvga_crtc_mask(stdvga_get_crtc(), 0x09, 0x1f, lines - 1);
269 }
270
271 // Get vertical display end
272 u16
273 stdvga_get_vde(void)
274 {
275     u16 crtc_addr = stdvga_get_crtc();
276     u16 vde = stdvga_crtc_read(crtc_addr, 0x12);
277     u8 ovl = stdvga_crtc_read(crtc_addr, 0x07);
278     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
279     return vde;
280 }
281
282 int
283 stdvga_get_window(struct vgamode_s *vmode_g, int window)
284 {
285     return -1;
286 }
287
288 int
289 stdvga_set_window(struct vgamode_s *vmode_g, int window, int val)
290 {
291     return -1;
292 }
293
294 int
295 stdvga_get_linelength(struct vgamode_s *vmode_g)
296 {
297     u8 val = stdvga_crtc_read(stdvga_get_crtc(), 0x13);
298     return val * stdvga_bpp_factor(vmode_g) * 2;
299 }
300
301 int
302 stdvga_set_linelength(struct vgamode_s *vmode_g, int val)
303 {
304     int factor = stdvga_bpp_factor(vmode_g) * 2;
305     stdvga_crtc_write(stdvga_get_crtc(), 0x13, DIV_ROUND_UP(val, factor));
306     return 0;
307 }
308
309 int
310 stdvga_get_displaystart(struct vgamode_s *vmode_g)
311 {
312     u16 crtc_addr = stdvga_get_crtc();
313     int addr = (stdvga_crtc_read(crtc_addr, 0x0c) << 8
314                 | stdvga_crtc_read(crtc_addr, 0x0d));
315     return addr * stdvga_bpp_factor(vmode_g);
316 }
317
318 int
319 stdvga_set_displaystart(struct vgamode_s *vmode_g, int val)
320 {
321     u16 crtc_addr = stdvga_get_crtc();
322     val /= stdvga_bpp_factor(vmode_g);
323     stdvga_crtc_write(crtc_addr, 0x0c, val >> 8);
324     stdvga_crtc_write(crtc_addr, 0x0d, val);
325     return 0;
326 }
327
328
329 /****************************************************************
330  * Save/Restore/Set state
331  ****************************************************************/
332
333 void
334 stdvga_save_state(u16 seg, struct saveVideoHardware *info)
335 {
336     u16 crtc_addr = stdvga_get_crtc();
337     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
338     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
339     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
340     SET_FARVAR(seg, info->actl_index, stdvga_attrindex_read());
341     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
342
343     int i;
344     for (i=0; i<4; i++)
345         SET_FARVAR(seg, info->sequ_regs[i], stdvga_sequ_read(i+1));
346     SET_FARVAR(seg, info->sequ0, stdvga_sequ_read(0));
347
348     for (i=0; i<25; i++)
349         SET_FARVAR(seg, info->crtc_regs[i], stdvga_crtc_read(crtc_addr, i));
350
351     for (i=0; i<20; i++)
352         SET_FARVAR(seg, info->actl_regs[i], stdvga_attr_read(i));
353
354     for (i=0; i<9; i++)
355         SET_FARVAR(seg, info->grdc_regs[i], stdvga_grdc_read(i));
356
357     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
358
359     /* XXX: read plane latches */
360     for (i=0; i<4; i++)
361         SET_FARVAR(seg, info->plane_latch[i], 0);
362 }
363
364 void
365 stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
366 {
367     int i;
368     for (i=0; i<4; i++)
369         stdvga_sequ_write(i+1, GET_FARVAR(seg, info->sequ_regs[i]));
370     stdvga_sequ_write(0x00, GET_FARVAR(seg, info->sequ0));
371
372     // Disable CRTC write protection
373     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
374     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
375     // Set CRTC regs
376     for (i=0; i<25; i++)
377         if (i != 0x11)
378             stdvga_crtc_write(crtc_addr, i, GET_FARVAR(seg, info->crtc_regs[i]));
379     // select crtc base address
380     stdvga_misc_mask(0x01, crtc_addr == VGAREG_VGA_CRTC_ADDRESS ? 0x01 : 0x00);
381
382     // enable write protection if needed
383     stdvga_crtc_write(crtc_addr, 0x11, GET_FARVAR(seg, info->crtc_regs[0x11]));
384
385     // Set Attribute Ctl
386     for (i=0; i<20; i++)
387         stdvga_attr_write(i, GET_FARVAR(seg, info->actl_regs[i]));
388     stdvga_attrindex_write(GET_FARVAR(seg, info->actl_index));
389
390     for (i=0; i<9; i++)
391         stdvga_grdc_write(i, GET_FARVAR(seg, info->grdc_regs[i]));
392
393     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
394     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
395     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
396     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
397 }
398
399 static void
400 clear_screen(struct vgamode_s *vmode_g)
401 {
402     switch (GET_GLOBAL(vmode_g->memmodel)) {
403     case MM_TEXT:
404         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
405         break;
406     case MM_CGA:
407         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
408         break;
409     default:
410         // XXX - old code gets/sets/restores sequ register 2 to 0xf -
411         // but it should always be 0xf anyway.
412         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
413     }
414 }
415
416 int
417 stdvga_set_mode(struct vgamode_s *vmode_g, int flags)
418 {
419     if (! stdvga_is_mode(vmode_g)) {
420         warn_internalerror();
421         return -1;
422     }
423     struct stdvga_mode_s *stdmode_g = container_of(
424         vmode_g, struct stdvga_mode_s, info);
425
426     // if palette loading (bit 3 of modeset ctl = 0)
427     if (!(flags & MF_NOPALETTE)) {    // Set the PEL mask
428         stdvga_pelmask_write(GET_GLOBAL(stdmode_g->pelmask));
429
430         // From which palette
431         u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
432         u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
433
434         // Always 256*3 values
435         stdvga_dac_write(get_global_seg(), palette_g, 0, palsize);
436         int i;
437         for (i = palsize; i < 0x0100; i++) {
438             static u8 rgb[3] VAR16;
439             stdvga_dac_write(get_global_seg(), rgb, i, 1);
440         }
441
442         if (flags & MF_GRAYSUM)
443             stdvga_perform_gray_scale_summing(0x00, 0x100);
444     }
445
446     // Set Attribute Ctl
447     u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
448     int i;
449     for (i = 0; i <= 0x13; i++)
450         stdvga_attr_write(i, GET_GLOBAL(regs[i]));
451     stdvga_attr_write(0x14, 0x00);
452
453     // Set Sequencer Ctl
454     stdvga_sequ_write(0x00, 0x03);
455     regs = GET_GLOBAL(stdmode_g->sequ_regs);
456     for (i = 1; i <= 4; i++)
457         stdvga_sequ_write(i, GET_GLOBAL(regs[i - 1]));
458
459     // Set Grafx Ctl
460     regs = GET_GLOBAL(stdmode_g->grdc_regs);
461     for (i = 0; i <= 8; i++)
462         stdvga_grdc_write(i, GET_GLOBAL(regs[i]));
463
464     // Set CRTC address VGA or MDA
465     u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
466     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
467     if (!(miscreg & 1))
468         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
469
470     // Disable CRTC write protection
471     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
472     // Set CRTC regs
473     regs = GET_GLOBAL(stdmode_g->crtc_regs);
474     for (i = 0; i <= 0x18; i++)
475         stdvga_crtc_write(crtc_addr, i, GET_GLOBAL(regs[i]));
476
477     // Set the misc register
478     stdvga_misc_write(miscreg);
479
480     // Enable video
481     stdvga_attrindex_write(0x20);
482
483     // Clear screen
484     if (!(flags & MF_NOCLEARMEM))
485         clear_screen(vmode_g);
486
487     // Write the fonts in memory
488     u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
489     if (memmodel == MM_TEXT)
490         stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
491
492     return 0;
493 }
494
495
496 /****************************************************************
497  * Misc
498  ****************************************************************/
499
500 void
501 stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
502 {
503     SET_FARVAR(seg, *dest, 0xffff);
504 }
505
506 void
507 stdvga_enable_video_addressing(u8 disable)
508 {
509     u8 v = (disable & 1) ? 0x00 : 0x02;
510     stdvga_misc_mask(0x02, v);
511 }
512
513 int
514 stdvga_init(void)
515 {
516     // switch to color mode and enable CPU access 480 lines
517     stdvga_misc_write(0xc3);
518     // more than 64k 3C4/04
519     stdvga_sequ_write(0x04, 0x02);
520
521     return 0;
522 }