blob: cb8793e69814ddba744ae6059197d831d7324fe4 [file] [log] [blame]
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001// VGA bios implementation
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
9// TODO:
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040010// * review correctness of converted asm by comparing with RBIL
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040011//
Kevin O'Connor6ace78f2009-05-14 19:24:49 -040012// * convert vbe/clext code
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040013
14#include "bregs.h" // struct bregs
15#include "biosvar.h" // GET_BDA
16#include "util.h" // memset
Kevin O'Connore1e000b2011-12-31 03:30:40 -050017#include "vgabios.h" // find_vga_entry
Julian Pidancet7c6509c2011-12-19 05:07:55 +000018#include "optionroms.h" // struct pci_data
19#include "config.h" // CONFIG_*
Kevin O'Connor88ca7412011-12-31 04:24:20 -050020#include "stdvga.h" // stdvga_screen_disable
Kevin O'Connor4c52fb42011-12-24 00:44:07 -050021#include "geodelx.h" // geodelx_init
Kevin O'Connorf1e217d2011-12-31 03:18:18 -050022#include "bochsvga.h" // bochsvga_init
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040023
24// XXX
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040025#define DEBUG_VGA_POST 1
26#define DEBUG_VGA_10 3
27
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040028
Julian Pidancet7c6509c2011-12-19 05:07:55 +000029/****************************************************************
30 * PCI Data
31 ****************************************************************/
32#if CONFIG_VGA_PCI == 1
33struct pci_data rom_pci_data VAR16VISIBLE = {
34 .signature = PCI_ROM_SIGNATURE,
35 .vendor = CONFIG_VGA_VID,
36 .device = CONFIG_VGA_DID,
37 .dlen = 0x18,
38 .class_hi = 0x300,
39 .irevision = 1,
40 .type = PCIROM_CODETYPE_X86,
41 .indicator = 0x80,
42};
43#endif
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040044
45/****************************************************************
46 * Helper functions
47 ****************************************************************/
48
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040049static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040050perform_gray_scale_summing(u16 start, u16 count)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040051{
Kevin O'Connor88ca7412011-12-31 04:24:20 -050052 stdvga_screen_disable();
Kevin O'Connordd2be772009-05-16 15:41:23 -040053 int i;
54 for (i = start; i < start+count; i++) {
Kevin O'Connora0ecb052009-05-18 23:34:00 -040055 u8 rgb[3];
Kevin O'Connor88ca7412011-12-31 04:24:20 -050056 stdvga_get_dac_regs(GET_SEG(SS), rgb, i, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040057
58 // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
Kevin O'Connora0ecb052009-05-18 23:34:00 -040059 u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
Kevin O'Connordd2be772009-05-16 15:41:23 -040060 if (intensity > 0x3f)
61 intensity = 0x3f;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040062
Kevin O'Connor88ca7412011-12-31 04:24:20 -050063 stdvga_set_dac_regs(GET_SEG(SS), rgb, i, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040064 }
Kevin O'Connor88ca7412011-12-31 04:24:20 -050065 stdvga_screen_enable();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040066}
67
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040068static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040069set_cursor_shape(u8 start, u8 end)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040070{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040071 start &= 0x3f;
72 end &= 0x1f;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040073
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040074 u16 curs = (start << 8) + end;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040075 SET_BDA(cursor_type, curs);
76
Kevin O'Connordd2be772009-05-16 15:41:23 -040077 u8 modeset_ctl = GET_BDA(modeset_ctl);
78 u16 cheight = GET_BDA(char_height);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040079 if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
80 if (end != (start + 1))
81 start = ((start + 1) * cheight / 8) - 1;
Kevin O'Connordd2be772009-05-16 15:41:23 -040082 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040083 start = ((end + 1) * cheight / 8) - 2;
84 end = ((end + 1) * cheight / 8) - 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040085 }
Kevin O'Connor88ca7412011-12-31 04:24:20 -050086 stdvga_set_cursor_shape(start, end);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040087}
88
Kevin O'Connor0818e1a2009-05-16 18:00:19 -040089static u16
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040090get_cursor_shape(u8 page)
Kevin O'Connor0818e1a2009-05-16 18:00:19 -040091{
92 if (page > 7)
93 return 0;
94 // FIXME should handle VGA 14/16 lines
95 return GET_BDA(cursor_type);
96}
97
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040098static void
Kevin O'Connor918b1562009-05-25 11:05:18 -040099set_cursor_pos(struct cursorpos cp)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400100{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400101 // Should not happen...
Kevin O'Connor918b1562009-05-25 11:05:18 -0400102 if (cp.page > 7)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400103 return;
104
105 // Bios cursor pos
Kevin O'Connor918b1562009-05-25 11:05:18 -0400106 SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400107
108 // Set the hardware cursor
Kevin O'Connordd2be772009-05-16 15:41:23 -0400109 u8 current = GET_BDA(video_page);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400110 if (cp.page != current)
Kevin O'Connordd2be772009-05-16 15:41:23 -0400111 return;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400112
Kevin O'Connordd2be772009-05-16 15:41:23 -0400113 // Get the dimensions
114 u16 nbcols = GET_BDA(video_cols);
115 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400116
Kevin O'Connordd2be772009-05-16 15:41:23 -0400117 // Calculate the address knowing nbcols nbrows and page num
Kevin O'Connor918b1562009-05-25 11:05:18 -0400118 u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
119 + cp.x + cp.y * nbcols);
Kevin O'Connordd2be772009-05-16 15:41:23 -0400120
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500121 stdvga_set_cursor_pos(address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400122}
123
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400124static struct cursorpos
Kevin O'Connor918b1562009-05-25 11:05:18 -0400125get_cursor_pos(u8 page)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400126{
Kevin O'Connor918b1562009-05-25 11:05:18 -0400127 if (page == 0xff)
128 // special case - use current page
129 page = GET_BDA(video_page);
130 if (page > 7) {
131 struct cursorpos cp = { 0, 0, 0xfe };
132 return cp;
133 }
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400134 // FIXME should handle VGA 14/16 lines
Kevin O'Connor918b1562009-05-25 11:05:18 -0400135 u16 xy = GET_BDA(cursor_pos[page]);
136 struct cursorpos cp = {xy, xy>>8, page};
137 return cp;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400138}
139
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400140static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400141set_active_page(u8 page)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400142{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400143 if (page > 7)
144 return;
145
146 // Get the mode
Kevin O'Connor5727c292009-05-16 17:29:32 -0400147 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
148 if (!vmode_g)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400149 return;
150
151 // Get pos curs pos for the right page
Kevin O'Connor918b1562009-05-25 11:05:18 -0400152 struct cursorpos cp = get_cursor_pos(page);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400153
Kevin O'Connordd2be772009-05-16 15:41:23 -0400154 u16 address;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400155 if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400156 // Get the dimensions
Kevin O'Connordd2be772009-05-16 15:41:23 -0400157 u16 nbcols = GET_BDA(video_cols);
158 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400159
160 // Calculate the address knowing nbcols nbrows and page num
161 address = SCREEN_MEM_START(nbcols, nbrows, page);
162 SET_BDA(video_pagestart, address);
163
164 // Start address
165 address = SCREEN_IO_START(nbcols, nbrows, page);
166 } else {
Kevin O'Connor87233e92011-12-23 21:40:34 -0500167 address = page * GET_GLOBAL(vmode_g->slength);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400168 }
169
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500170 stdvga_set_active_page(address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400171
172 // And change the BIOS page
173 SET_BDA(video_page, page);
174
Kevin O'Connora12c2152009-05-13 22:06:16 -0400175 dprintf(1, "Set active page %02x address %04x\n", page, address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400176
177 // Display the cursor, now the page is active
Kevin O'Connor918b1562009-05-25 11:05:18 -0400178 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400179}
180
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400181static void
182set_scan_lines(u8 lines)
183{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500184 stdvga_set_scan_lines(lines);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400185 if (lines == 8)
186 set_cursor_shape(0x06, 0x07);
187 else
188 set_cursor_shape(lines - 4, lines - 3);
189 SET_BDA(char_height, lines);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500190 u16 vde = stdvga_get_vde();
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400191 u8 rows = vde / lines;
192 SET_BDA(video_rows, rows - 1);
193 u16 cols = GET_BDA(video_cols);
194 SET_BDA(video_pagesize, rows * cols * 2);
195}
196
197
198/****************************************************************
199 * Character writing
200 ****************************************************************/
201
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400202// Scroll the screen one line. This function is designed to be called
203// tail-recursive to reduce stack usage.
204static void noinline
205scroll_one(u16 nbrows, u16 nbcols, u8 page)
Kevin O'Connor09262412009-05-25 11:44:11 -0400206{
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400207 struct cursorpos ul = {0, 0, page};
208 struct cursorpos lr = {nbcols-1, nbrows-1, page};
209 vgafb_scroll(1, -1, ul, lr);
210}
211
212// Write a character to the screen at a given position. Implement
213// special characters and scroll the screen if necessary.
214static void
215write_teletype(struct cursorpos *pcp, struct carattr ca)
216{
217 struct cursorpos cp = *pcp;
218
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400219 // Get the dimensions
Kevin O'Connordd2be772009-05-16 15:41:23 -0400220 u16 nbrows = GET_BDA(video_rows) + 1;
221 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400222
Kevin O'Connor2e86c6a2009-05-31 20:43:06 -0400223 switch (ca.car) {
224 case 7:
225 //FIXME should beep
226 break;
227 case 8:
228 if (cp.x > 0)
229 cp.x--;
230 break;
231 case '\r':
232 cp.x = 0;
233 break;
234 case '\n':
235 cp.y++;
236 break;
237 case '\t':
238 do {
239 struct carattr dummyca = {' ', ca.attr, ca.use_attr};
240 vgafb_write_char(cp, dummyca);
241 cp.x++;
242 } while (cp.x < nbcols && cp.x % 8);
243 break;
244 default:
245 vgafb_write_char(cp, ca);
246 cp.x++;
247 }
248
Kevin O'Connor82221b22009-05-26 00:20:40 -0400249 // Do we need to wrap ?
250 if (cp.x == nbcols) {
251 cp.x = 0;
252 cp.y++;
253 }
254 // Do we need to scroll ?
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400255 if (cp.y < nbrows) {
256 *pcp = cp;
257 return;
Kevin O'Connor82221b22009-05-26 00:20:40 -0400258 }
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400259 // Scroll screen
260 cp.y--;
261 *pcp = cp;
262 scroll_one(nbrows, nbcols, cp.page);
Kevin O'Connor82221b22009-05-26 00:20:40 -0400263}
264
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400265// Write out a buffer of alternating characters and attributes.
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400266static void
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400267write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400268{
Kevin O'Connor2e86c6a2009-05-31 20:43:06 -0400269 while (count--) {
Kevin O'Connordd2be772009-05-16 15:41:23 -0400270 u8 car = GET_FARVAR(seg, *offset_far);
271 offset_far++;
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400272 u8 attr = GET_FARVAR(seg, *offset_far);
273 offset_far++;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400274
Kevin O'Connor09262412009-05-25 11:44:11 -0400275 struct carattr ca = {car, attr, 1};
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400276 write_teletype(pcp, ca);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400277 }
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400278}
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400279
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400280// Write out a buffer of characters.
281static void
282write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far)
283{
284 while (count--) {
285 u8 car = GET_FARVAR(seg, *offset_far);
286 offset_far++;
287
288 struct carattr ca = {car, attr, 1};
289 write_teletype(pcp, ca);
290 }
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400291}
292
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400293
294/****************************************************************
295 * Save and restore bda state
296 ****************************************************************/
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400297
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400298static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400299save_bda_state(u16 seg, struct saveBDAstate *info)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400300{
Kevin O'Connorca668642009-05-21 23:06:08 -0400301 SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
302 SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
303 SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
304 SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
305 SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
306 SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
307 SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
308 SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
309 SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
310 SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
311 u16 i;
312 for (i=0; i<8; i++)
313 SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
314 SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
315 SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
316 /* current font */
Kevin O'Connor9f985422009-09-09 11:34:39 -0400317 SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
318 SET_FARVAR(seg, info->font1, GET_IVT(0x43));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400319}
320
Kevin O'Connorca668642009-05-21 23:06:08 -0400321static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400322restore_bda_state(u16 seg, struct saveBDAstate *info)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400323{
Kevin O'Connorca668642009-05-21 23:06:08 -0400324 SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
325 SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
326 SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
327 SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
328 SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
329 SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
330 SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
331 SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
332 SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
333 SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
334 u16 i;
335 for (i = 0; i < 8; i++)
336 SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
337 SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
338 SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
339 /* current font */
Kevin O'Connor9f985422009-09-09 11:34:39 -0400340 SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
341 SET_IVT(0x43, GET_FARVAR(seg, info->font1));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400342}
343
344
345/****************************************************************
346 * VGA int 10 handler
347 ****************************************************************/
348
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400349// set video mode
Julian Pidancet87879e22011-12-19 05:08:00 +0000350void
351vga_set_mode(u8 mode, u8 noclearmem)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400352{
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400353 // find the entry in the video modes
354 struct vgamode_s *vmode_g = find_vga_entry(mode);
355 dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
356 if (!vmode_g)
357 return;
358
359 // Read the bios mode set control
360 u8 modeset_ctl = GET_BDA(modeset_ctl);
361
362 // Then we know the number of lines
363// FIXME
364
365 // if palette loading (bit 3 of modeset ctl = 0)
366 if ((modeset_ctl & 0x08) == 0) { // Set the PEL mask
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500367 stdvga_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400368
369 // From which palette
370 u8 *palette_g = GET_GLOBAL(vmode_g->dac);
371 u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
372
373 // Always 256*3 values
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500374 stdvga_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400375 u16 i;
376 for (i = palsize; i < 0x0100; i++) {
377 static u8 rgb[3] VAR16;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500378 stdvga_set_dac_regs(get_global_seg(), rgb, i, 1);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400379 }
380
381 if ((modeset_ctl & 0x02) == 0x02)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400382 perform_gray_scale_summing(0x00, 0x100);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400383 }
384
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500385 stdvga_set_mode(vmode_g);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400386
387 if (noclearmem == 0x00)
388 clear_screen(vmode_g);
389
Kevin O'Connorcecbc5d2011-12-31 17:24:11 -0500390 // Write the fonts in memory
391 u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
392 if (memmodel & TEXT)
393 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400394
395 // Set the BIOS mem
Kevin O'Connor87233e92011-12-23 21:40:34 -0500396 u16 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400397 SET_BDA(video_mode, mode);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500398 SET_BDA(video_cols, GET_GLOBAL(vmode_g->twidth));
399 SET_BDA(video_pagesize, GET_GLOBAL(vmode_g->slength));
Kevin O'Connorcecbc5d2011-12-31 17:24:11 -0500400 SET_BDA(crtc_address, stdvga_get_crtc());
Kevin O'Connor87233e92011-12-23 21:40:34 -0500401 SET_BDA(video_rows, GET_GLOBAL(vmode_g->theight)-1);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400402 SET_BDA(char_height, cheight);
403 SET_BDA(video_ctl, (0x60 | noclearmem));
404 SET_BDA(video_switches, 0xF9);
405 SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
Kevin O'Connorcecbc5d2011-12-31 17:24:11 -0500406 SET_BDA(cursor_type, memmodel & TEXT ? 0x0607 : 0x0000);
407 int i;
408 for (i=0; i<8; i++)
409 SET_BDA(cursor_pos[i], 0x0000);
410 SET_BDA(video_pagestart, 0x0000);
411 SET_BDA(video_page, 0x00);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400412
413 // FIXME We nearly have the good tables. to be reworked
414 SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
Kevin O'Connor9f985422009-09-09 11:34:39 -0400415 SET_BDA(video_savetable
Kevin O'Connor815e4472011-12-21 09:05:32 -0500416 , SEGOFF(get_global_seg(), (u32)&video_save_pointer_table));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400417
418 // FIXME
419 SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
420 SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
421
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400422 // Set the ints 0x1F and 0x43
Kevin O'Connor9f985422009-09-09 11:34:39 -0400423 SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400424
425 switch (cheight) {
426 case 8:
Kevin O'Connor9f985422009-09-09 11:34:39 -0400427 SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400428 break;
429 case 14:
Kevin O'Connor9f985422009-09-09 11:34:39 -0400430 SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400431 break;
432 case 16:
Kevin O'Connor9f985422009-09-09 11:34:39 -0400433 SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400434 break;
435 }
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400436}
437
438static void
Julian Pidancet87879e22011-12-19 05:08:00 +0000439handle_1000(struct bregs *regs)
440{
441 u8 noclearmem = regs->al & 0x80;
442 u8 mode = regs->al & 0x7f;
443
444 // Set regs->al
445 if (mode > 7)
446 regs->al = 0x20;
447 else if (mode == 6)
448 regs->al = 0x3f;
449 else
450 regs->al = 0x30;
451
Kevin O'Connore48a5372011-12-20 23:56:14 -0500452 if (CONFIG_VGA_CIRRUS) {
453 int ret = cirrus_set_video_mode(mode, noclearmem);
454 if (ret)
455 return;
456 }
Julian Pidancet87879e22011-12-19 05:08:00 +0000457
Kevin O'Connorf1e217d2011-12-31 03:18:18 -0500458 if (bochsvga_enabled())
459 bochsvga_hires_enable(0);
Julian Pidancet87879e22011-12-19 05:08:00 +0000460
461 vga_set_mode(mode, noclearmem);
462}
463
464static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400465handle_1001(struct bregs *regs)
466{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400467 set_cursor_shape(regs->ch, regs->cl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400468}
469
470static void
471handle_1002(struct bregs *regs)
472{
Kevin O'Connor918b1562009-05-25 11:05:18 -0400473 struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
474 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400475}
476
477static void
478handle_1003(struct bregs *regs)
479{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400480 regs->cx = get_cursor_shape(regs->bh);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400481 struct cursorpos cp = get_cursor_pos(regs->bh);
482 regs->dl = cp.x;
483 regs->dh = cp.y;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400484}
485
486// Read light pen pos (unimplemented)
487static void
488handle_1004(struct bregs *regs)
489{
490 debug_stub(regs);
491 regs->ax = regs->bx = regs->cx = regs->dx = 0;
492}
493
494static void
495handle_1005(struct bregs *regs)
496{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400497 set_active_page(regs->al);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400498}
499
500static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400501verify_scroll(struct bregs *regs, int dir)
502{
503 u8 page = GET_BDA(video_page);
504 struct cursorpos ul = {regs->cl, regs->ch, page};
505 struct cursorpos lr = {regs->dl, regs->dh, page};
506
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400507 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400508 if (lr.y >= nbrows)
509 lr.y = nbrows - 1;
Kevin O'Connorc3e15872009-05-31 01:37:54 -0400510 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400511 if (lr.x >= nbcols)
512 lr.x = nbcols - 1;
513
Kevin O'Connorc3e15872009-05-31 01:37:54 -0400514 if (ul.x > lr.x || ul.y > lr.y)
515 return;
516
517 u16 nblines = regs->al;
518 if (!nblines || nblines > lr.y - ul.y + 1)
519 nblines = lr.y - ul.y + 1;
520
521 vgafb_scroll(dir * nblines, regs->bh, ul, lr);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400522}
523
524static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400525handle_1006(struct bregs *regs)
526{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400527 verify_scroll(regs, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400528}
529
530static void
531handle_1007(struct bregs *regs)
532{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400533 verify_scroll(regs, -1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400534}
535
536static void
537handle_1008(struct bregs *regs)
538{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400539 struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
Kevin O'Connor09262412009-05-25 11:44:11 -0400540 regs->al = ca.car;
541 regs->ah = ca.attr;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400542}
543
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400544static void noinline
Kevin O'Connord3b38152009-05-26 00:05:37 -0400545write_chars(u8 page, struct carattr ca, u16 count)
546{
547 struct cursorpos cp = get_cursor_pos(page);
548 while (count--) {
549 vgafb_write_char(cp, ca);
550 cp.x++;
551 }
552}
553
554static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400555handle_1009(struct bregs *regs)
556{
Kevin O'Connor09262412009-05-25 11:44:11 -0400557 struct carattr ca = {regs->al, regs->bl, 1};
Kevin O'Connord3b38152009-05-26 00:05:37 -0400558 write_chars(regs->bh, ca, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400559}
560
561static void
562handle_100a(struct bregs *regs)
563{
Kevin O'Connor09262412009-05-25 11:44:11 -0400564 struct carattr ca = {regs->al, regs->bl, 0};
Kevin O'Connord3b38152009-05-26 00:05:37 -0400565 write_chars(regs->bh, ca, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400566}
567
568
569static void
570handle_100b00(struct bregs *regs)
571{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500572 stdvga_set_border_color(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400573}
574
575static void
576handle_100b01(struct bregs *regs)
577{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500578 stdvga_set_palette(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400579}
580
581static void
582handle_100bXX(struct bregs *regs)
583{
584 debug_stub(regs);
585}
586
587static void
588handle_100b(struct bregs *regs)
589{
590 switch (regs->bh) {
591 case 0x00: handle_100b00(regs); break;
592 case 0x01: handle_100b01(regs); break;
593 default: handle_100bXX(regs); break;
594 }
595}
596
597
598static void
599handle_100c(struct bregs *regs)
600{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400601 // XXX - page (regs->bh) is unused
602 vgafb_write_pixel(regs->al, regs->cx, regs->dx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400603}
604
605static void
606handle_100d(struct bregs *regs)
607{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400608 // XXX - page (regs->bh) is unused
609 regs->al = vgafb_read_pixel(regs->cx, regs->dx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400610}
611
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400612static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400613handle_100e(struct bregs *regs)
614{
615 // Ralf Brown Interrupt list is WRONG on bh(page)
616 // We do output only on the current page !
Kevin O'Connor09262412009-05-25 11:44:11 -0400617 struct carattr ca = {regs->al, regs->bl, 0};
Kevin O'Connor116a0442009-05-26 00:47:32 -0400618 struct cursorpos cp = get_cursor_pos(0xff);
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400619 write_teletype(&cp, ca);
Kevin O'Connor116a0442009-05-26 00:47:32 -0400620 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400621}
622
623static void
624handle_100f(struct bregs *regs)
625{
Kevin O'Connore7132042009-05-25 00:10:35 -0400626 regs->bh = GET_BDA(video_page);
627 regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
628 regs->ah = GET_BDA(video_cols);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400629}
630
631
632static void
633handle_101000(struct bregs *regs)
634{
635 if (regs->bl > 0x14)
636 return;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500637 stdvga_set_single_palette_reg(regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400638}
639
640static void
641handle_101001(struct bregs *regs)
642{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500643 stdvga_set_overscan_border_color(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400644}
645
646static void
647handle_101002(struct bregs *regs)
648{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500649 stdvga_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400650}
651
652static void
653handle_101003(struct bregs *regs)
654{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500655 stdvga_toggle_intensity(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400656}
657
658static void
659handle_101007(struct bregs *regs)
660{
661 if (regs->bl > 0x14)
662 return;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500663 regs->bh = stdvga_get_single_palette_reg(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400664}
665
666static void
667handle_101008(struct bregs *regs)
668{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500669 regs->bh = stdvga_get_overscan_border_color();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400670}
671
672static void
673handle_101009(struct bregs *regs)
674{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500675 stdvga_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400676}
677
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400678static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400679handle_101010(struct bregs *regs)
680{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400681 u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500682 stdvga_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400683}
684
685static void
686handle_101012(struct bregs *regs)
687{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500688 stdvga_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400689}
690
691static void
692handle_101013(struct bregs *regs)
693{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500694 stdvga_select_video_dac_color_page(regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400695}
696
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400697static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400698handle_101015(struct bregs *regs)
699{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400700 u8 rgb[3];
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500701 stdvga_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400702 regs->dh = rgb[0];
703 regs->ch = rgb[1];
704 regs->cl = rgb[2];
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400705}
706
707static void
708handle_101017(struct bregs *regs)
709{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500710 stdvga_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400711}
712
713static void
714handle_101018(struct bregs *regs)
715{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500716 stdvga_set_pel_mask(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400717}
718
719static void
720handle_101019(struct bregs *regs)
721{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500722 regs->bl = stdvga_get_pel_mask();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400723}
724
725static void
726handle_10101a(struct bregs *regs)
727{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500728 stdvga_read_video_dac_state(&regs->bl, &regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400729}
730
731static void
732handle_10101b(struct bregs *regs)
733{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400734 perform_gray_scale_summing(regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400735}
736
737static void
738handle_1010XX(struct bregs *regs)
739{
740 debug_stub(regs);
741}
742
743static void
744handle_1010(struct bregs *regs)
745{
746 switch (regs->al) {
747 case 0x00: handle_101000(regs); break;
748 case 0x01: handle_101001(regs); break;
749 case 0x02: handle_101002(regs); break;
750 case 0x03: handle_101003(regs); break;
751 case 0x07: handle_101007(regs); break;
752 case 0x08: handle_101008(regs); break;
753 case 0x09: handle_101009(regs); break;
754 case 0x10: handle_101010(regs); break;
755 case 0x12: handle_101012(regs); break;
756 case 0x13: handle_101013(regs); break;
757 case 0x15: handle_101015(regs); break;
758 case 0x17: handle_101017(regs); break;
759 case 0x18: handle_101018(regs); break;
760 case 0x19: handle_101019(regs); break;
761 case 0x1a: handle_10101a(regs); break;
762 case 0x1b: handle_10101b(regs); break;
763 default: handle_1010XX(regs); break;
764 }
765}
766
767
768static void
769handle_101100(struct bregs *regs)
770{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500771 stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
772 , regs->dx, regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400773}
774
775static void
776handle_101101(struct bregs *regs)
777{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500778 stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400779}
780
781static void
782handle_101102(struct bregs *regs)
783{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500784 stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400785}
786
787static void
788handle_101103(struct bregs *regs)
789{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500790 stdvga_set_text_block_specifier(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400791}
792
793static void
794handle_101104(struct bregs *regs)
795{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500796 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400797}
798
799static void
800handle_101110(struct bregs *regs)
801{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500802 stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
803 , regs->dx, regs->bl, regs->bh);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400804 set_scan_lines(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400805}
806
807static void
808handle_101111(struct bregs *regs)
809{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500810 stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400811 set_scan_lines(14);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400812}
813
814static void
815handle_101112(struct bregs *regs)
816{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500817 stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400818 set_scan_lines(8);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400819}
820
821static void
822handle_101114(struct bregs *regs)
823{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500824 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400825 set_scan_lines(16);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400826}
827
828static void
829handle_101130(struct bregs *regs)
830{
Kevin O'Connore7132042009-05-25 00:10:35 -0400831 switch (regs->bh) {
832 case 0x00: {
Kevin O'Connorc9d3c2d2010-01-01 12:53:32 -0500833 struct segoff_s so = GET_IVT(0x1f);
834 regs->es = so.seg;
835 regs->bp = so.offset;
Kevin O'Connore7132042009-05-25 00:10:35 -0400836 break;
837 }
838 case 0x01: {
Kevin O'Connorc9d3c2d2010-01-01 12:53:32 -0500839 struct segoff_s so = GET_IVT(0x43);
840 regs->es = so.seg;
841 regs->bp = so.offset;
Kevin O'Connore7132042009-05-25 00:10:35 -0400842 break;
843 }
844 case 0x02:
845 regs->es = get_global_seg();
846 regs->bp = (u32)vgafont14;
847 break;
848 case 0x03:
849 regs->es = get_global_seg();
850 regs->bp = (u32)vgafont8;
851 break;
852 case 0x04:
853 regs->es = get_global_seg();
854 regs->bp = (u32)vgafont8 + 128 * 8;
855 break;
856 case 0x05:
857 regs->es = get_global_seg();
858 regs->bp = (u32)vgafont14alt;
859 break;
860 case 0x06:
861 regs->es = get_global_seg();
862 regs->bp = (u32)vgafont16;
863 break;
864 case 0x07:
865 regs->es = get_global_seg();
866 regs->bp = (u32)vgafont16alt;
867 break;
868 default:
869 dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
870 return;
871 }
872 // Set byte/char of on screen font
873 regs->cx = GET_BDA(char_height) & 0xff;
874
875 // Set Highest char row
876 regs->dx = GET_BDA(video_rows);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400877}
878
879static void
880handle_1011XX(struct bregs *regs)
881{
882 debug_stub(regs);
883}
884
885static void
886handle_1011(struct bregs *regs)
887{
888 switch (regs->al) {
889 case 0x00: handle_101100(regs); break;
890 case 0x01: handle_101101(regs); break;
891 case 0x02: handle_101102(regs); break;
892 case 0x03: handle_101103(regs); break;
893 case 0x04: handle_101104(regs); break;
894 case 0x10: handle_101110(regs); break;
895 case 0x11: handle_101111(regs); break;
896 case 0x12: handle_101112(regs); break;
897 case 0x14: handle_101114(regs); break;
898 case 0x30: handle_101130(regs); break;
899 default: handle_1011XX(regs); break;
900 }
901}
902
903
904static void
905handle_101210(struct bregs *regs)
906{
Kevin O'Connore7132042009-05-25 00:10:35 -0400907 u16 crtc_addr = GET_BDA(crtc_address);
908 if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
909 regs->bx = 0x0103;
910 else
911 regs->bx = 0x0003;
912 regs->cx = GET_BDA(video_switches) & 0x0f;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400913}
914
915static void
916handle_101230(struct bregs *regs)
917{
Kevin O'Connore7132042009-05-25 00:10:35 -0400918 u8 mctl = GET_BDA(modeset_ctl);
919 u8 vswt = GET_BDA(video_switches);
920 switch (regs->al) {
921 case 0x00:
922 // 200 lines
923 mctl = (mctl & ~0x10) | 0x80;
924 vswt = (vswt & ~0x0f) | 0x08;
925 break;
926 case 0x01:
927 // 350 lines
928 mctl &= ~0x90;
929 vswt = (vswt & ~0x0f) | 0x09;
930 break;
931 case 0x02:
932 // 400 lines
933 mctl = (mctl & ~0x80) | 0x10;
934 vswt = (vswt & ~0x0f) | 0x09;
935 break;
936 default:
937 dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
938 break;
939 }
940 SET_BDA(modeset_ctl, mctl);
941 SET_BDA(video_switches, vswt);
942 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400943}
944
945static void
946handle_101231(struct bregs *regs)
947{
Kevin O'Connore7132042009-05-25 00:10:35 -0400948 u8 v = (regs->al & 0x01) << 3;
949 u8 mctl = GET_BDA(video_ctl) & ~0x08;
950 SET_BDA(video_ctl, mctl | v);
951 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400952}
953
954static void
955handle_101232(struct bregs *regs)
956{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500957 stdvga_enable_video_addressing(regs->al);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400958 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400959}
960
961static void
962handle_101233(struct bregs *regs)
963{
Kevin O'Connore7132042009-05-25 00:10:35 -0400964 u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
965 u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
966 SET_BDA(modeset_ctl, v | v2);
967 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400968}
969
970static void
971handle_101234(struct bregs *regs)
972{
Kevin O'Connore7132042009-05-25 00:10:35 -0400973 u8 v = (regs->al & 0x01) ^ 0x01;
974 u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
975 SET_BDA(modeset_ctl, v | v2);
976 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400977}
978
979static void
980handle_101235(struct bregs *regs)
981{
982 debug_stub(regs);
983 regs->al = 0x12;
984}
985
986static void
987handle_101236(struct bregs *regs)
988{
989 debug_stub(regs);
990 regs->al = 0x12;
991}
992
993static void
994handle_1012XX(struct bregs *regs)
995{
996 debug_stub(regs);
997}
998
999static void
1000handle_1012(struct bregs *regs)
1001{
1002 switch (regs->bl) {
1003 case 0x10: handle_101210(regs); break;
1004 case 0x30: handle_101230(regs); break;
1005 case 0x31: handle_101231(regs); break;
1006 case 0x32: handle_101232(regs); break;
1007 case 0x33: handle_101233(regs); break;
1008 case 0x34: handle_101234(regs); break;
1009 case 0x35: handle_101235(regs); break;
1010 case 0x36: handle_101236(regs); break;
1011 default: handle_1012XX(regs); break;
1012 }
1013
1014 // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
1015}
1016
1017
Kevin O'Connorafb287d2009-05-31 21:15:33 -04001018// Write string
Kevin O'Connor0ad77f02009-05-31 20:46:43 -04001019static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001020handle_1013(struct bregs *regs)
1021{
Kevin O'Connor918b1562009-05-25 11:05:18 -04001022 struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
Kevin O'Connor2e86c6a2009-05-31 20:43:06 -04001023 // if row=0xff special case : use current cursor position
1024 if (cp.y == 0xff)
1025 cp = get_cursor_pos(cp.page);
Kevin O'Connorafb287d2009-05-31 21:15:33 -04001026 u8 flag = regs->al;
1027 if (flag & 2)
1028 write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0));
1029 else
1030 write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0));
1031
1032 if (flag & 1)
1033 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001034}
1035
1036
1037static void
1038handle_101a00(struct bregs *regs)
1039{
Kevin O'Connore7132042009-05-25 00:10:35 -04001040 regs->bx = GET_BDA(dcc_index);
1041 regs->al = 0x1a;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001042}
1043
1044static void
1045handle_101a01(struct bregs *regs)
1046{
Kevin O'Connore7132042009-05-25 00:10:35 -04001047 SET_BDA(dcc_index, regs->bl);
1048 dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
1049 regs->al = 0x1a;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001050}
1051
1052static void
1053handle_101aXX(struct bregs *regs)
1054{
1055 debug_stub(regs);
1056}
1057
1058static void
1059handle_101a(struct bregs *regs)
1060{
1061 switch (regs->al) {
1062 case 0x00: handle_101a00(regs); break;
1063 case 0x01: handle_101a01(regs); break;
1064 default: handle_101aXX(regs); break;
1065 }
1066}
1067
1068
Kevin O'Connorca668642009-05-21 23:06:08 -04001069struct funcInfo {
Kevin O'Connor87dfad32011-12-23 21:18:49 -05001070 struct segoff_s static_functionality;
Kevin O'Connorca668642009-05-21 23:06:08 -04001071 u8 bda_0x49[30];
1072 u8 bda_0x84[3];
1073 u8 dcc_index;
1074 u8 dcc_alt;
1075 u16 colors;
1076 u8 pages;
1077 u8 scan_lines;
1078 u8 primary_char;
1079 u8 secondar_char;
1080 u8 misc;
1081 u8 non_vga_mode;
1082 u8 reserved_2f[2];
1083 u8 video_mem;
1084 u8 save_flags;
1085 u8 disp_info;
1086 u8 reserved_34[12];
1087};
1088
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001089static void
1090handle_101b(struct bregs *regs)
1091{
Kevin O'Connorca668642009-05-21 23:06:08 -04001092 u16 seg = regs->es;
1093 struct funcInfo *info = (void*)(regs->di+0);
1094 memset_far(seg, info, 0, sizeof(*info));
1095 // Address of static functionality table
Kevin O'Connor87dfad32011-12-23 21:18:49 -05001096 SET_FARVAR(seg, info->static_functionality
1097 , SEGOFF(get_global_seg(), (u32)static_functionality));
Kevin O'Connorca668642009-05-21 23:06:08 -04001098
1099 // Hard coded copy from BIOS area. Should it be cleaner ?
Kevin O'Connor9f985422009-09-09 11:34:39 -04001100 memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
1101 , sizeof(info->bda_0x49));
1102 memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
1103 , sizeof(info->bda_0x84));
Kevin O'Connorca668642009-05-21 23:06:08 -04001104
1105 SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
1106 SET_FARVAR(seg, info->colors, 16);
1107 SET_FARVAR(seg, info->pages, 8);
1108 SET_FARVAR(seg, info->scan_lines, 2);
1109 SET_FARVAR(seg, info->video_mem, 3);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001110 regs->al = 0x1B;
1111}
1112
1113
1114static void
1115handle_101c00(struct bregs *regs)
1116{
Kevin O'Connorca668642009-05-21 23:06:08 -04001117 u16 flags = regs->cx;
1118 u16 size = 0;
1119 if (flags & 1)
1120 size += sizeof(struct saveVideoHardware);
1121 if (flags & 2)
1122 size += sizeof(struct saveBDAstate);
1123 if (flags & 4)
1124 size += sizeof(struct saveDACcolors);
1125 regs->bx = size;
1126 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001127}
1128
1129static void
1130handle_101c01(struct bregs *regs)
1131{
Kevin O'Connorca668642009-05-21 23:06:08 -04001132 u16 flags = regs->cx;
1133 u16 seg = regs->es;
1134 void *data = (void*)(regs->bx+0);
1135 if (flags & 1) {
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001136 stdvga_save_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001137 data += sizeof(struct saveVideoHardware);
1138 }
1139 if (flags & 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -04001140 save_bda_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001141 data += sizeof(struct saveBDAstate);
1142 }
1143 if (flags & 4)
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001144 stdvga_save_dac_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001145 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001146}
1147
1148static void
1149handle_101c02(struct bregs *regs)
1150{
Kevin O'Connorca668642009-05-21 23:06:08 -04001151 u16 flags = regs->cx;
1152 u16 seg = regs->es;
1153 void *data = (void*)(regs->bx+0);
1154 if (flags & 1) {
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001155 stdvga_restore_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001156 data += sizeof(struct saveVideoHardware);
1157 }
1158 if (flags & 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -04001159 restore_bda_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001160 data += sizeof(struct saveBDAstate);
1161 }
1162 if (flags & 4)
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001163 stdvga_restore_dac_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001164 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001165}
1166
1167static void
1168handle_101cXX(struct bregs *regs)
1169{
1170 debug_stub(regs);
1171}
1172
1173static void
1174handle_101c(struct bregs *regs)
1175{
1176 switch (regs->al) {
1177 case 0x00: handle_101c00(regs); break;
1178 case 0x01: handle_101c01(regs); break;
1179 case 0x02: handle_101c02(regs); break;
1180 default: handle_101cXX(regs); break;
1181 }
1182}
1183
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001184static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001185handle_10XX(struct bregs *regs)
1186{
1187 debug_stub(regs);
1188}
1189
1190// INT 10h Video Support Service Entry Point
1191void VISIBLE16
1192handle_10(struct bregs *regs)
1193{
1194 debug_enter(regs, DEBUG_VGA_10);
1195 switch (regs->ah) {
1196 case 0x00: handle_1000(regs); break;
1197 case 0x01: handle_1001(regs); break;
1198 case 0x02: handle_1002(regs); break;
1199 case 0x03: handle_1003(regs); break;
1200 case 0x04: handle_1004(regs); break;
1201 case 0x05: handle_1005(regs); break;
1202 case 0x06: handle_1006(regs); break;
1203 case 0x07: handle_1007(regs); break;
1204 case 0x08: handle_1008(regs); break;
1205 case 0x09: handle_1009(regs); break;
1206 case 0x0a: handle_100a(regs); break;
1207 case 0x0b: handle_100b(regs); break;
1208 case 0x0c: handle_100c(regs); break;
1209 case 0x0d: handle_100d(regs); break;
1210 case 0x0e: handle_100e(regs); break;
1211 case 0x0f: handle_100f(regs); break;
1212 case 0x10: handle_1010(regs); break;
1213 case 0x11: handle_1011(regs); break;
1214 case 0x12: handle_1012(regs); break;
1215 case 0x13: handle_1013(regs); break;
1216 case 0x1a: handle_101a(regs); break;
1217 case 0x1b: handle_101b(regs); break;
1218 case 0x1c: handle_101c(regs); break;
1219 case 0x4f: handle_104f(regs); break;
1220 default: handle_10XX(regs); break;
1221 }
1222}
1223
1224
1225/****************************************************************
1226 * VGA post
1227 ****************************************************************/
1228
1229static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -05001230init_bios_area(void)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001231{
1232 // init detected hardware BIOS Area
1233 // set 80x25 color (not clear from RBIL but usual)
1234 u16 eqf = GET_BDA(equipment_list_flags);
1235 SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1236
1237 // Just for the first int10 find its children
1238
1239 // the default char height
1240 SET_BDA(char_height, 0x10);
1241
1242 // Clear the screen
1243 SET_BDA(video_ctl, 0x60);
1244
1245 // Set the basic screen we have
1246 SET_BDA(video_switches, 0xf9);
1247
1248 // Set the basic modeset options
1249 SET_BDA(modeset_ctl, 0x51);
1250
1251 // Set the default MSR
1252 SET_BDA(video_msr, 0x09);
1253}
1254
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001255void VISIBLE16
1256vga_post(struct bregs *regs)
1257{
1258 debug_enter(regs, DEBUG_VGA_POST);
1259
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001260 stdvga_init();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001261
Kevin O'Connor4c52fb42011-12-24 00:44:07 -05001262 if (CONFIG_VGA_GEODELX)
1263 geodelx_init();
1264
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001265 init_bios_area();
1266
Kevin O'Connorf1e217d2011-12-31 03:18:18 -05001267 bochsvga_init(regs->ah, regs->al);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001268
1269 extern void entry_10(void);
Kevin O'Connor9f985422009-09-09 11:34:39 -04001270 SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001271
Julian Pidancet677631f2011-12-19 05:07:53 +00001272 if (CONFIG_VGA_CIRRUS)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001273 cirrus_init();
1274
1275 // XXX - clear screen and display info
1276
Kevin O'Connorf3760372011-12-23 22:41:08 -05001277 build_video_param();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001278
1279 // Fixup checksum
1280 extern u8 _rom_header_size, _rom_header_checksum;
1281 SET_VGA(_rom_header_checksum, 0);
Kevin O'Connord113a992009-05-16 21:05:02 -04001282 u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001283 SET_VGA(_rom_header_checksum, sum);
1284}