blob: 7d558c182012e525bf6bef48bdaf7dae4523f724 [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'Connor821d6b42011-12-31 18:19:22 -050020#include "stdvga.h" // stdvga_set_mode
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'Connor6f775082011-12-31 18:39:59 -050023#include "clext.h" // clext_init
Kevin O'Connor5108c692011-12-31 19:13:45 -050024#include "vgahw.h" // vgahw_set_mode
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040025
26// XXX
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040027#define DEBUG_VGA_POST 1
28#define DEBUG_VGA_10 3
29
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040030
Julian Pidancet7c6509c2011-12-19 05:07:55 +000031/****************************************************************
32 * PCI Data
33 ****************************************************************/
34#if CONFIG_VGA_PCI == 1
35struct pci_data rom_pci_data VAR16VISIBLE = {
36 .signature = PCI_ROM_SIGNATURE,
37 .vendor = CONFIG_VGA_VID,
38 .device = CONFIG_VGA_DID,
39 .dlen = 0x18,
40 .class_hi = 0x300,
41 .irevision = 1,
42 .type = PCIROM_CODETYPE_X86,
43 .indicator = 0x80,
44};
45#endif
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040046
47/****************************************************************
48 * Helper functions
49 ****************************************************************/
50
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040051static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040052set_cursor_shape(u8 start, u8 end)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040053{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040054 start &= 0x3f;
55 end &= 0x1f;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040056
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040057 u16 curs = (start << 8) + end;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040058 SET_BDA(cursor_type, curs);
59
Kevin O'Connordd2be772009-05-16 15:41:23 -040060 u8 modeset_ctl = GET_BDA(modeset_ctl);
61 u16 cheight = GET_BDA(char_height);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040062 if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
63 if (end != (start + 1))
64 start = ((start + 1) * cheight / 8) - 1;
Kevin O'Connordd2be772009-05-16 15:41:23 -040065 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040066 start = ((end + 1) * cheight / 8) - 2;
67 end = ((end + 1) * cheight / 8) - 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040068 }
Kevin O'Connor88ca7412011-12-31 04:24:20 -050069 stdvga_set_cursor_shape(start, end);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040070}
71
Kevin O'Connor0818e1a2009-05-16 18:00:19 -040072static u16
Kevin O'Connor227a2bb2009-05-31 22:00:20 -040073get_cursor_shape(u8 page)
Kevin O'Connor0818e1a2009-05-16 18:00:19 -040074{
75 if (page > 7)
76 return 0;
77 // FIXME should handle VGA 14/16 lines
78 return GET_BDA(cursor_type);
79}
80
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040081static void
Kevin O'Connor918b1562009-05-25 11:05:18 -040082set_cursor_pos(struct cursorpos cp)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040083{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040084 // Should not happen...
Kevin O'Connor918b1562009-05-25 11:05:18 -040085 if (cp.page > 7)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040086 return;
87
88 // Bios cursor pos
Kevin O'Connor918b1562009-05-25 11:05:18 -040089 SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040090
91 // Set the hardware cursor
Kevin O'Connordd2be772009-05-16 15:41:23 -040092 u8 current = GET_BDA(video_page);
Kevin O'Connor918b1562009-05-25 11:05:18 -040093 if (cp.page != current)
Kevin O'Connordd2be772009-05-16 15:41:23 -040094 return;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040095
Kevin O'Connordd2be772009-05-16 15:41:23 -040096 // Get the dimensions
97 u16 nbcols = GET_BDA(video_cols);
98 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -040099
Kevin O'Connordd2be772009-05-16 15:41:23 -0400100 // Calculate the address knowing nbcols nbrows and page num
Kevin O'Connor918b1562009-05-25 11:05:18 -0400101 u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
102 + cp.x + cp.y * nbcols);
Kevin O'Connordd2be772009-05-16 15:41:23 -0400103
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500104 stdvga_set_cursor_pos(address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400105}
106
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400107static struct cursorpos
Kevin O'Connor918b1562009-05-25 11:05:18 -0400108get_cursor_pos(u8 page)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400109{
Kevin O'Connor918b1562009-05-25 11:05:18 -0400110 if (page == 0xff)
111 // special case - use current page
112 page = GET_BDA(video_page);
113 if (page > 7) {
114 struct cursorpos cp = { 0, 0, 0xfe };
115 return cp;
116 }
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400117 // FIXME should handle VGA 14/16 lines
Kevin O'Connor918b1562009-05-25 11:05:18 -0400118 u16 xy = GET_BDA(cursor_pos[page]);
119 struct cursorpos cp = {xy, xy>>8, page};
120 return cp;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400121}
122
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400123static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400124set_active_page(u8 page)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400125{
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400126 if (page > 7)
127 return;
128
129 // Get the mode
Kevin O'Connor5727c292009-05-16 17:29:32 -0400130 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
131 if (!vmode_g)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400132 return;
133
134 // Get pos curs pos for the right page
Kevin O'Connor918b1562009-05-25 11:05:18 -0400135 struct cursorpos cp = get_cursor_pos(page);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400136
Kevin O'Connordd2be772009-05-16 15:41:23 -0400137 u16 address;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400138 if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400139 // Get the dimensions
Kevin O'Connordd2be772009-05-16 15:41:23 -0400140 u16 nbcols = GET_BDA(video_cols);
141 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400142
143 // Calculate the address knowing nbcols nbrows and page num
144 address = SCREEN_MEM_START(nbcols, nbrows, page);
145 SET_BDA(video_pagestart, address);
146
147 // Start address
148 address = SCREEN_IO_START(nbcols, nbrows, page);
149 } else {
Kevin O'Connor87233e92011-12-23 21:40:34 -0500150 address = page * GET_GLOBAL(vmode_g->slength);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400151 }
152
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500153 stdvga_set_active_page(address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400154
155 // And change the BIOS page
156 SET_BDA(video_page, page);
157
Kevin O'Connora12c2152009-05-13 22:06:16 -0400158 dprintf(1, "Set active page %02x address %04x\n", page, address);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400159
160 // Display the cursor, now the page is active
Kevin O'Connor918b1562009-05-25 11:05:18 -0400161 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400162}
163
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400164static void
165set_scan_lines(u8 lines)
166{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500167 stdvga_set_scan_lines(lines);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400168 if (lines == 8)
169 set_cursor_shape(0x06, 0x07);
170 else
171 set_cursor_shape(lines - 4, lines - 3);
172 SET_BDA(char_height, lines);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500173 u16 vde = stdvga_get_vde();
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400174 u8 rows = vde / lines;
175 SET_BDA(video_rows, rows - 1);
176 u16 cols = GET_BDA(video_cols);
177 SET_BDA(video_pagesize, rows * cols * 2);
178}
179
180
181/****************************************************************
182 * Character writing
183 ****************************************************************/
184
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400185// Scroll the screen one line. This function is designed to be called
186// tail-recursive to reduce stack usage.
187static void noinline
188scroll_one(u16 nbrows, u16 nbcols, u8 page)
Kevin O'Connor09262412009-05-25 11:44:11 -0400189{
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400190 struct cursorpos ul = {0, 0, page};
191 struct cursorpos lr = {nbcols-1, nbrows-1, page};
192 vgafb_scroll(1, -1, ul, lr);
193}
194
195// Write a character to the screen at a given position. Implement
196// special characters and scroll the screen if necessary.
197static void
198write_teletype(struct cursorpos *pcp, struct carattr ca)
199{
200 struct cursorpos cp = *pcp;
201
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400202 // Get the dimensions
Kevin O'Connordd2be772009-05-16 15:41:23 -0400203 u16 nbrows = GET_BDA(video_rows) + 1;
204 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400205
Kevin O'Connor2e86c6a2009-05-31 20:43:06 -0400206 switch (ca.car) {
207 case 7:
208 //FIXME should beep
209 break;
210 case 8:
211 if (cp.x > 0)
212 cp.x--;
213 break;
214 case '\r':
215 cp.x = 0;
216 break;
217 case '\n':
218 cp.y++;
219 break;
220 case '\t':
221 do {
222 struct carattr dummyca = {' ', ca.attr, ca.use_attr};
223 vgafb_write_char(cp, dummyca);
224 cp.x++;
225 } while (cp.x < nbcols && cp.x % 8);
226 break;
227 default:
228 vgafb_write_char(cp, ca);
229 cp.x++;
230 }
231
Kevin O'Connor82221b22009-05-26 00:20:40 -0400232 // Do we need to wrap ?
233 if (cp.x == nbcols) {
234 cp.x = 0;
235 cp.y++;
236 }
237 // Do we need to scroll ?
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400238 if (cp.y < nbrows) {
239 *pcp = cp;
240 return;
Kevin O'Connor82221b22009-05-26 00:20:40 -0400241 }
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400242 // Scroll screen
243 cp.y--;
244 *pcp = cp;
245 scroll_one(nbrows, nbcols, cp.page);
Kevin O'Connor82221b22009-05-26 00:20:40 -0400246}
247
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400248// Write out a buffer of alternating characters and attributes.
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400249static void
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400250write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400251{
Kevin O'Connor2e86c6a2009-05-31 20:43:06 -0400252 while (count--) {
Kevin O'Connordd2be772009-05-16 15:41:23 -0400253 u8 car = GET_FARVAR(seg, *offset_far);
254 offset_far++;
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400255 u8 attr = GET_FARVAR(seg, *offset_far);
256 offset_far++;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400257
Kevin O'Connor09262412009-05-25 11:44:11 -0400258 struct carattr ca = {car, attr, 1};
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400259 write_teletype(pcp, ca);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400260 }
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400261}
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400262
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400263// Write out a buffer of characters.
264static void
265write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far)
266{
267 while (count--) {
268 u8 car = GET_FARVAR(seg, *offset_far);
269 offset_far++;
270
271 struct carattr ca = {car, attr, 1};
272 write_teletype(pcp, ca);
273 }
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400274}
275
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400276
277/****************************************************************
278 * Save and restore bda state
279 ****************************************************************/
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400280
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400281static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400282save_bda_state(u16 seg, struct saveBDAstate *info)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400283{
Kevin O'Connorca668642009-05-21 23:06:08 -0400284 SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
285 SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
286 SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
287 SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
288 SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
289 SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
290 SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
291 SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
292 SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
293 SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
294 u16 i;
295 for (i=0; i<8; i++)
296 SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
297 SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
298 SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
299 /* current font */
Kevin O'Connor9f985422009-09-09 11:34:39 -0400300 SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
301 SET_FARVAR(seg, info->font1, GET_IVT(0x43));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400302}
303
Kevin O'Connorca668642009-05-21 23:06:08 -0400304static void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400305restore_bda_state(u16 seg, struct saveBDAstate *info)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400306{
Kevin O'Connorca668642009-05-21 23:06:08 -0400307 SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
308 SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
309 SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
310 SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
311 SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
312 SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
313 SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
314 SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
315 SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
316 SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
317 u16 i;
318 for (i = 0; i < 8; i++)
319 SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
320 SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
321 SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
322 /* current font */
Kevin O'Connor9f985422009-09-09 11:34:39 -0400323 SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
324 SET_IVT(0x43, GET_FARVAR(seg, info->font1));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400325}
326
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500327// Setup BDA after a mode switch.
Julian Pidancet87879e22011-12-19 05:08:00 +0000328void
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500329modeswitch_set_bda(int mode, int flags, struct vgamode_s *vmode_g)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400330{
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400331 // Set the BIOS mem
Kevin O'Connor87233e92011-12-23 21:40:34 -0500332 u16 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400333 SET_BDA(video_mode, mode);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500334 SET_BDA(video_cols, GET_GLOBAL(vmode_g->twidth));
335 SET_BDA(video_pagesize, GET_GLOBAL(vmode_g->slength));
Kevin O'Connorcecbc5d2011-12-31 17:24:11 -0500336 SET_BDA(crtc_address, stdvga_get_crtc());
Kevin O'Connor87233e92011-12-23 21:40:34 -0500337 SET_BDA(video_rows, GET_GLOBAL(vmode_g->theight)-1);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400338 SET_BDA(char_height, cheight);
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500339 SET_BDA(video_ctl, 0x60 | (flags & MF_NOCLEARMEM ? 0x80 : 0x00));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400340 SET_BDA(video_switches, 0xF9);
341 SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500342 SET_BDA(cursor_type, GET_GLOBAL(vmode_g->memmodel) & TEXT ? 0x0607 : 0x0000);
Kevin O'Connorcecbc5d2011-12-31 17:24:11 -0500343 int i;
344 for (i=0; i<8; i++)
345 SET_BDA(cursor_pos[i], 0x0000);
346 SET_BDA(video_pagestart, 0x0000);
347 SET_BDA(video_page, 0x00);
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400348
349 // FIXME We nearly have the good tables. to be reworked
350 SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
Kevin O'Connor9f985422009-09-09 11:34:39 -0400351 SET_BDA(video_savetable
Kevin O'Connor815e4472011-12-21 09:05:32 -0500352 , SEGOFF(get_global_seg(), (u32)&video_save_pointer_table));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400353
354 // FIXME
355 SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
356 SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
357
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400358 // Set the ints 0x1F and 0x43
Kevin O'Connor9f985422009-09-09 11:34:39 -0400359 SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400360
361 switch (cheight) {
362 case 8:
Kevin O'Connor9f985422009-09-09 11:34:39 -0400363 SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400364 break;
365 case 14:
Kevin O'Connor9f985422009-09-09 11:34:39 -0400366 SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400367 break;
368 case 16:
Kevin O'Connor9f985422009-09-09 11:34:39 -0400369 SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
Kevin O'Connor85ea07e2009-05-25 09:41:07 -0400370 break;
371 }
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400372}
373
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500374
375/****************************************************************
376 * VGA int 10 handler
377 ****************************************************************/
378
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400379static void
Julian Pidancet87879e22011-12-19 05:08:00 +0000380handle_1000(struct bregs *regs)
381{
Kevin O'Connor5108c692011-12-31 19:13:45 -0500382 int mode = regs->al & 0x7f;
Julian Pidancet87879e22011-12-19 05:08:00 +0000383
384 // Set regs->al
385 if (mode > 7)
386 regs->al = 0x20;
387 else if (mode == 6)
388 regs->al = 0x3f;
389 else
390 regs->al = 0x30;
391
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500392 int flags = GET_BDA(modeset_ctl) & (MF_NOPALETTE|MF_GRAYSUM);
Kevin O'Connor5108c692011-12-31 19:13:45 -0500393 if (regs->al & 0x80)
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500394 flags |= MF_NOCLEARMEM;
395
Kevin O'Connor5108c692011-12-31 19:13:45 -0500396 vgahw_set_mode(mode, flags);
Julian Pidancet87879e22011-12-19 05:08:00 +0000397}
398
399static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400400handle_1001(struct bregs *regs)
401{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400402 set_cursor_shape(regs->ch, regs->cl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400403}
404
405static void
406handle_1002(struct bregs *regs)
407{
Kevin O'Connor918b1562009-05-25 11:05:18 -0400408 struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
409 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400410}
411
412static void
413handle_1003(struct bregs *regs)
414{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400415 regs->cx = get_cursor_shape(regs->bh);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400416 struct cursorpos cp = get_cursor_pos(regs->bh);
417 regs->dl = cp.x;
418 regs->dh = cp.y;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400419}
420
421// Read light pen pos (unimplemented)
422static void
423handle_1004(struct bregs *regs)
424{
425 debug_stub(regs);
426 regs->ax = regs->bx = regs->cx = regs->dx = 0;
427}
428
429static void
430handle_1005(struct bregs *regs)
431{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400432 set_active_page(regs->al);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400433}
434
435static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400436verify_scroll(struct bregs *regs, int dir)
437{
438 u8 page = GET_BDA(video_page);
439 struct cursorpos ul = {regs->cl, regs->ch, page};
440 struct cursorpos lr = {regs->dl, regs->dh, page};
441
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400442 u16 nbrows = GET_BDA(video_rows) + 1;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400443 if (lr.y >= nbrows)
444 lr.y = nbrows - 1;
Kevin O'Connorc3e15872009-05-31 01:37:54 -0400445 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400446 if (lr.x >= nbcols)
447 lr.x = nbcols - 1;
448
Kevin O'Connorc3e15872009-05-31 01:37:54 -0400449 if (ul.x > lr.x || ul.y > lr.y)
450 return;
451
452 u16 nblines = regs->al;
453 if (!nblines || nblines > lr.y - ul.y + 1)
454 nblines = lr.y - ul.y + 1;
455
456 vgafb_scroll(dir * nblines, regs->bh, ul, lr);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400457}
458
459static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400460handle_1006(struct bregs *regs)
461{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400462 verify_scroll(regs, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400463}
464
465static void
466handle_1007(struct bregs *regs)
467{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400468 verify_scroll(regs, -1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400469}
470
471static void
472handle_1008(struct bregs *regs)
473{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400474 struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
Kevin O'Connor09262412009-05-25 11:44:11 -0400475 regs->al = ca.car;
476 regs->ah = ca.attr;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400477}
478
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400479static void noinline
Kevin O'Connord3b38152009-05-26 00:05:37 -0400480write_chars(u8 page, struct carattr ca, u16 count)
481{
482 struct cursorpos cp = get_cursor_pos(page);
483 while (count--) {
484 vgafb_write_char(cp, ca);
485 cp.x++;
486 }
487}
488
489static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400490handle_1009(struct bregs *regs)
491{
Kevin O'Connor09262412009-05-25 11:44:11 -0400492 struct carattr ca = {regs->al, regs->bl, 1};
Kevin O'Connord3b38152009-05-26 00:05:37 -0400493 write_chars(regs->bh, ca, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400494}
495
496static void
497handle_100a(struct bregs *regs)
498{
Kevin O'Connor09262412009-05-25 11:44:11 -0400499 struct carattr ca = {regs->al, regs->bl, 0};
Kevin O'Connord3b38152009-05-26 00:05:37 -0400500 write_chars(regs->bh, ca, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400501}
502
503
504static void
505handle_100b00(struct bregs *regs)
506{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500507 stdvga_set_border_color(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400508}
509
510static void
511handle_100b01(struct bregs *regs)
512{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500513 stdvga_set_palette(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400514}
515
516static void
517handle_100bXX(struct bregs *regs)
518{
519 debug_stub(regs);
520}
521
522static void
523handle_100b(struct bregs *regs)
524{
525 switch (regs->bh) {
526 case 0x00: handle_100b00(regs); break;
527 case 0x01: handle_100b01(regs); break;
528 default: handle_100bXX(regs); break;
529 }
530}
531
532
533static void
534handle_100c(struct bregs *regs)
535{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400536 // XXX - page (regs->bh) is unused
537 vgafb_write_pixel(regs->al, regs->cx, regs->dx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400538}
539
540static void
541handle_100d(struct bregs *regs)
542{
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400543 // XXX - page (regs->bh) is unused
544 regs->al = vgafb_read_pixel(regs->cx, regs->dx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400545}
546
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400547static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400548handle_100e(struct bregs *regs)
549{
550 // Ralf Brown Interrupt list is WRONG on bh(page)
551 // We do output only on the current page !
Kevin O'Connor09262412009-05-25 11:44:11 -0400552 struct carattr ca = {regs->al, regs->bl, 0};
Kevin O'Connor116a0442009-05-26 00:47:32 -0400553 struct cursorpos cp = get_cursor_pos(0xff);
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400554 write_teletype(&cp, ca);
Kevin O'Connor116a0442009-05-26 00:47:32 -0400555 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400556}
557
558static void
559handle_100f(struct bregs *regs)
560{
Kevin O'Connore7132042009-05-25 00:10:35 -0400561 regs->bh = GET_BDA(video_page);
562 regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
563 regs->ah = GET_BDA(video_cols);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400564}
565
566
567static void
568handle_101000(struct bregs *regs)
569{
570 if (regs->bl > 0x14)
571 return;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500572 stdvga_set_single_palette_reg(regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400573}
574
575static void
576handle_101001(struct bregs *regs)
577{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500578 stdvga_set_overscan_border_color(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400579}
580
581static void
582handle_101002(struct bregs *regs)
583{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500584 stdvga_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400585}
586
587static void
588handle_101003(struct bregs *regs)
589{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500590 stdvga_toggle_intensity(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400591}
592
593static void
594handle_101007(struct bregs *regs)
595{
596 if (regs->bl > 0x14)
597 return;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500598 regs->bh = stdvga_get_single_palette_reg(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400599}
600
601static void
602handle_101008(struct bregs *regs)
603{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500604 regs->bh = stdvga_get_overscan_border_color();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400605}
606
607static void
608handle_101009(struct bregs *regs)
609{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500610 stdvga_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400611}
612
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400613static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400614handle_101010(struct bregs *regs)
615{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400616 u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500617 stdvga_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400618}
619
620static void
621handle_101012(struct bregs *regs)
622{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500623 stdvga_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400624}
625
626static void
627handle_101013(struct bregs *regs)
628{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500629 stdvga_select_video_dac_color_page(regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400630}
631
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400632static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400633handle_101015(struct bregs *regs)
634{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400635 u8 rgb[3];
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500636 stdvga_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400637 regs->dh = rgb[0];
638 regs->ch = rgb[1];
639 regs->cl = rgb[2];
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400640}
641
642static void
643handle_101017(struct bregs *regs)
644{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500645 stdvga_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400646}
647
648static void
649handle_101018(struct bregs *regs)
650{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500651 stdvga_set_pel_mask(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400652}
653
654static void
655handle_101019(struct bregs *regs)
656{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500657 regs->bl = stdvga_get_pel_mask();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400658}
659
660static void
661handle_10101a(struct bregs *regs)
662{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500663 stdvga_read_video_dac_state(&regs->bl, &regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400664}
665
666static void
667handle_10101b(struct bregs *regs)
668{
Kevin O'Connor821d6b42011-12-31 18:19:22 -0500669 stdvga_perform_gray_scale_summing(regs->bx, regs->cx);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400670}
671
672static void
673handle_1010XX(struct bregs *regs)
674{
675 debug_stub(regs);
676}
677
678static void
679handle_1010(struct bregs *regs)
680{
681 switch (regs->al) {
682 case 0x00: handle_101000(regs); break;
683 case 0x01: handle_101001(regs); break;
684 case 0x02: handle_101002(regs); break;
685 case 0x03: handle_101003(regs); break;
686 case 0x07: handle_101007(regs); break;
687 case 0x08: handle_101008(regs); break;
688 case 0x09: handle_101009(regs); break;
689 case 0x10: handle_101010(regs); break;
690 case 0x12: handle_101012(regs); break;
691 case 0x13: handle_101013(regs); break;
692 case 0x15: handle_101015(regs); break;
693 case 0x17: handle_101017(regs); break;
694 case 0x18: handle_101018(regs); break;
695 case 0x19: handle_101019(regs); break;
696 case 0x1a: handle_10101a(regs); break;
697 case 0x1b: handle_10101b(regs); break;
698 default: handle_1010XX(regs); break;
699 }
700}
701
702
703static void
704handle_101100(struct bregs *regs)
705{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500706 stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
707 , regs->dx, regs->bl, regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400708}
709
710static void
711handle_101101(struct bregs *regs)
712{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500713 stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400714}
715
716static void
717handle_101102(struct bregs *regs)
718{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500719 stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400720}
721
722static void
723handle_101103(struct bregs *regs)
724{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500725 stdvga_set_text_block_specifier(regs->bl);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400726}
727
728static void
729handle_101104(struct bregs *regs)
730{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500731 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400732}
733
734static void
735handle_101110(struct bregs *regs)
736{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500737 stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
738 , regs->dx, regs->bl, regs->bh);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400739 set_scan_lines(regs->bh);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400740}
741
742static void
743handle_101111(struct bregs *regs)
744{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500745 stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400746 set_scan_lines(14);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400747}
748
749static void
750handle_101112(struct bregs *regs)
751{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500752 stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400753 set_scan_lines(8);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400754}
755
756static void
757handle_101114(struct bregs *regs)
758{
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500759 stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400760 set_scan_lines(16);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400761}
762
763static void
764handle_101130(struct bregs *regs)
765{
Kevin O'Connore7132042009-05-25 00:10:35 -0400766 switch (regs->bh) {
767 case 0x00: {
Kevin O'Connorc9d3c2d2010-01-01 12:53:32 -0500768 struct segoff_s so = GET_IVT(0x1f);
769 regs->es = so.seg;
770 regs->bp = so.offset;
Kevin O'Connore7132042009-05-25 00:10:35 -0400771 break;
772 }
773 case 0x01: {
Kevin O'Connorc9d3c2d2010-01-01 12:53:32 -0500774 struct segoff_s so = GET_IVT(0x43);
775 regs->es = so.seg;
776 regs->bp = so.offset;
Kevin O'Connore7132042009-05-25 00:10:35 -0400777 break;
778 }
779 case 0x02:
780 regs->es = get_global_seg();
781 regs->bp = (u32)vgafont14;
782 break;
783 case 0x03:
784 regs->es = get_global_seg();
785 regs->bp = (u32)vgafont8;
786 break;
787 case 0x04:
788 regs->es = get_global_seg();
789 regs->bp = (u32)vgafont8 + 128 * 8;
790 break;
791 case 0x05:
792 regs->es = get_global_seg();
793 regs->bp = (u32)vgafont14alt;
794 break;
795 case 0x06:
796 regs->es = get_global_seg();
797 regs->bp = (u32)vgafont16;
798 break;
799 case 0x07:
800 regs->es = get_global_seg();
801 regs->bp = (u32)vgafont16alt;
802 break;
803 default:
804 dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
805 return;
806 }
807 // Set byte/char of on screen font
808 regs->cx = GET_BDA(char_height) & 0xff;
809
810 // Set Highest char row
811 regs->dx = GET_BDA(video_rows);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400812}
813
814static void
815handle_1011XX(struct bregs *regs)
816{
817 debug_stub(regs);
818}
819
820static void
821handle_1011(struct bregs *regs)
822{
823 switch (regs->al) {
824 case 0x00: handle_101100(regs); break;
825 case 0x01: handle_101101(regs); break;
826 case 0x02: handle_101102(regs); break;
827 case 0x03: handle_101103(regs); break;
828 case 0x04: handle_101104(regs); break;
829 case 0x10: handle_101110(regs); break;
830 case 0x11: handle_101111(regs); break;
831 case 0x12: handle_101112(regs); break;
832 case 0x14: handle_101114(regs); break;
833 case 0x30: handle_101130(regs); break;
834 default: handle_1011XX(regs); break;
835 }
836}
837
838
839static void
840handle_101210(struct bregs *regs)
841{
Kevin O'Connore7132042009-05-25 00:10:35 -0400842 u16 crtc_addr = GET_BDA(crtc_address);
843 if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
844 regs->bx = 0x0103;
845 else
846 regs->bx = 0x0003;
847 regs->cx = GET_BDA(video_switches) & 0x0f;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400848}
849
850static void
851handle_101230(struct bregs *regs)
852{
Kevin O'Connore7132042009-05-25 00:10:35 -0400853 u8 mctl = GET_BDA(modeset_ctl);
854 u8 vswt = GET_BDA(video_switches);
855 switch (regs->al) {
856 case 0x00:
857 // 200 lines
858 mctl = (mctl & ~0x10) | 0x80;
859 vswt = (vswt & ~0x0f) | 0x08;
860 break;
861 case 0x01:
862 // 350 lines
863 mctl &= ~0x90;
864 vswt = (vswt & ~0x0f) | 0x09;
865 break;
866 case 0x02:
867 // 400 lines
868 mctl = (mctl & ~0x80) | 0x10;
869 vswt = (vswt & ~0x0f) | 0x09;
870 break;
871 default:
872 dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
873 break;
874 }
875 SET_BDA(modeset_ctl, mctl);
876 SET_BDA(video_switches, vswt);
877 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400878}
879
880static void
881handle_101231(struct bregs *regs)
882{
Kevin O'Connore7132042009-05-25 00:10:35 -0400883 u8 v = (regs->al & 0x01) << 3;
884 u8 mctl = GET_BDA(video_ctl) & ~0x08;
885 SET_BDA(video_ctl, mctl | v);
886 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400887}
888
889static void
890handle_101232(struct bregs *regs)
891{
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500892 stdvga_enable_video_addressing(regs->al);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400893 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400894}
895
896static void
897handle_101233(struct bregs *regs)
898{
Kevin O'Connore7132042009-05-25 00:10:35 -0400899 u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
900 u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
901 SET_BDA(modeset_ctl, v | v2);
902 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400903}
904
905static void
906handle_101234(struct bregs *regs)
907{
Kevin O'Connore7132042009-05-25 00:10:35 -0400908 u8 v = (regs->al & 0x01) ^ 0x01;
909 u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
910 SET_BDA(modeset_ctl, v | v2);
911 regs->al = 0x12;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400912}
913
914static void
915handle_101235(struct bregs *regs)
916{
917 debug_stub(regs);
918 regs->al = 0x12;
919}
920
921static void
922handle_101236(struct bregs *regs)
923{
924 debug_stub(regs);
925 regs->al = 0x12;
926}
927
928static void
929handle_1012XX(struct bregs *regs)
930{
931 debug_stub(regs);
932}
933
934static void
935handle_1012(struct bregs *regs)
936{
937 switch (regs->bl) {
938 case 0x10: handle_101210(regs); break;
939 case 0x30: handle_101230(regs); break;
940 case 0x31: handle_101231(regs); break;
941 case 0x32: handle_101232(regs); break;
942 case 0x33: handle_101233(regs); break;
943 case 0x34: handle_101234(regs); break;
944 case 0x35: handle_101235(regs); break;
945 case 0x36: handle_101236(regs); break;
946 default: handle_1012XX(regs); break;
947 }
948
949 // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
950}
951
952
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400953// Write string
Kevin O'Connor0ad77f02009-05-31 20:46:43 -0400954static void noinline
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400955handle_1013(struct bregs *regs)
956{
Kevin O'Connor918b1562009-05-25 11:05:18 -0400957 struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
Kevin O'Connor2e86c6a2009-05-31 20:43:06 -0400958 // if row=0xff special case : use current cursor position
959 if (cp.y == 0xff)
960 cp = get_cursor_pos(cp.page);
Kevin O'Connorafb287d2009-05-31 21:15:33 -0400961 u8 flag = regs->al;
962 if (flag & 2)
963 write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0));
964 else
965 write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0));
966
967 if (flag & 1)
968 set_cursor_pos(cp);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400969}
970
971
972static void
973handle_101a00(struct bregs *regs)
974{
Kevin O'Connore7132042009-05-25 00:10:35 -0400975 regs->bx = GET_BDA(dcc_index);
976 regs->al = 0x1a;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400977}
978
979static void
980handle_101a01(struct bregs *regs)
981{
Kevin O'Connore7132042009-05-25 00:10:35 -0400982 SET_BDA(dcc_index, regs->bl);
983 dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
984 regs->al = 0x1a;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -0400985}
986
987static void
988handle_101aXX(struct bregs *regs)
989{
990 debug_stub(regs);
991}
992
993static void
994handle_101a(struct bregs *regs)
995{
996 switch (regs->al) {
997 case 0x00: handle_101a00(regs); break;
998 case 0x01: handle_101a01(regs); break;
999 default: handle_101aXX(regs); break;
1000 }
1001}
1002
1003
Kevin O'Connorca668642009-05-21 23:06:08 -04001004struct funcInfo {
Kevin O'Connor87dfad32011-12-23 21:18:49 -05001005 struct segoff_s static_functionality;
Kevin O'Connorca668642009-05-21 23:06:08 -04001006 u8 bda_0x49[30];
1007 u8 bda_0x84[3];
1008 u8 dcc_index;
1009 u8 dcc_alt;
1010 u16 colors;
1011 u8 pages;
1012 u8 scan_lines;
1013 u8 primary_char;
1014 u8 secondar_char;
1015 u8 misc;
1016 u8 non_vga_mode;
1017 u8 reserved_2f[2];
1018 u8 video_mem;
1019 u8 save_flags;
1020 u8 disp_info;
1021 u8 reserved_34[12];
1022};
1023
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001024static void
1025handle_101b(struct bregs *regs)
1026{
Kevin O'Connorca668642009-05-21 23:06:08 -04001027 u16 seg = regs->es;
1028 struct funcInfo *info = (void*)(regs->di+0);
1029 memset_far(seg, info, 0, sizeof(*info));
1030 // Address of static functionality table
Kevin O'Connor87dfad32011-12-23 21:18:49 -05001031 SET_FARVAR(seg, info->static_functionality
1032 , SEGOFF(get_global_seg(), (u32)static_functionality));
Kevin O'Connorca668642009-05-21 23:06:08 -04001033
1034 // Hard coded copy from BIOS area. Should it be cleaner ?
Kevin O'Connor9f985422009-09-09 11:34:39 -04001035 memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
1036 , sizeof(info->bda_0x49));
1037 memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
1038 , sizeof(info->bda_0x84));
Kevin O'Connorca668642009-05-21 23:06:08 -04001039
1040 SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
1041 SET_FARVAR(seg, info->colors, 16);
1042 SET_FARVAR(seg, info->pages, 8);
1043 SET_FARVAR(seg, info->scan_lines, 2);
1044 SET_FARVAR(seg, info->video_mem, 3);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001045 regs->al = 0x1B;
1046}
1047
1048
1049static void
1050handle_101c00(struct bregs *regs)
1051{
Kevin O'Connorca668642009-05-21 23:06:08 -04001052 u16 flags = regs->cx;
1053 u16 size = 0;
1054 if (flags & 1)
1055 size += sizeof(struct saveVideoHardware);
1056 if (flags & 2)
1057 size += sizeof(struct saveBDAstate);
1058 if (flags & 4)
1059 size += sizeof(struct saveDACcolors);
1060 regs->bx = size;
1061 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001062}
1063
1064static void
1065handle_101c01(struct bregs *regs)
1066{
Kevin O'Connorca668642009-05-21 23:06:08 -04001067 u16 flags = regs->cx;
1068 u16 seg = regs->es;
1069 void *data = (void*)(regs->bx+0);
1070 if (flags & 1) {
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001071 stdvga_save_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001072 data += sizeof(struct saveVideoHardware);
1073 }
1074 if (flags & 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -04001075 save_bda_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001076 data += sizeof(struct saveBDAstate);
1077 }
1078 if (flags & 4)
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001079 stdvga_save_dac_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001080 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001081}
1082
1083static void
1084handle_101c02(struct bregs *regs)
1085{
Kevin O'Connorca668642009-05-21 23:06:08 -04001086 u16 flags = regs->cx;
1087 u16 seg = regs->es;
1088 void *data = (void*)(regs->bx+0);
1089 if (flags & 1) {
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001090 stdvga_restore_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001091 data += sizeof(struct saveVideoHardware);
1092 }
1093 if (flags & 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -04001094 restore_bda_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001095 data += sizeof(struct saveBDAstate);
1096 }
1097 if (flags & 4)
Kevin O'Connor88ca7412011-12-31 04:24:20 -05001098 stdvga_restore_dac_state(seg, data);
Kevin O'Connorca668642009-05-21 23:06:08 -04001099 regs->al = 0x1c;
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001100}
1101
1102static void
1103handle_101cXX(struct bregs *regs)
1104{
1105 debug_stub(regs);
1106}
1107
1108static void
1109handle_101c(struct bregs *regs)
1110{
1111 switch (regs->al) {
1112 case 0x00: handle_101c00(regs); break;
1113 case 0x01: handle_101c01(regs); break;
1114 case 0x02: handle_101c02(regs); break;
1115 default: handle_101cXX(regs); break;
1116 }
1117}
1118
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001119static void
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001120handle_10XX(struct bregs *regs)
1121{
1122 debug_stub(regs);
1123}
1124
1125// INT 10h Video Support Service Entry Point
1126void VISIBLE16
1127handle_10(struct bregs *regs)
1128{
1129 debug_enter(regs, DEBUG_VGA_10);
1130 switch (regs->ah) {
1131 case 0x00: handle_1000(regs); break;
1132 case 0x01: handle_1001(regs); break;
1133 case 0x02: handle_1002(regs); break;
1134 case 0x03: handle_1003(regs); break;
1135 case 0x04: handle_1004(regs); break;
1136 case 0x05: handle_1005(regs); break;
1137 case 0x06: handle_1006(regs); break;
1138 case 0x07: handle_1007(regs); break;
1139 case 0x08: handle_1008(regs); break;
1140 case 0x09: handle_1009(regs); break;
1141 case 0x0a: handle_100a(regs); break;
1142 case 0x0b: handle_100b(regs); break;
1143 case 0x0c: handle_100c(regs); break;
1144 case 0x0d: handle_100d(regs); break;
1145 case 0x0e: handle_100e(regs); break;
1146 case 0x0f: handle_100f(regs); break;
1147 case 0x10: handle_1010(regs); break;
1148 case 0x11: handle_1011(regs); break;
1149 case 0x12: handle_1012(regs); break;
1150 case 0x13: handle_1013(regs); break;
1151 case 0x1a: handle_101a(regs); break;
1152 case 0x1b: handle_101b(regs); break;
1153 case 0x1c: handle_101c(regs); break;
1154 case 0x4f: handle_104f(regs); break;
1155 default: handle_10XX(regs); break;
1156 }
1157}
1158
1159
1160/****************************************************************
1161 * VGA post
1162 ****************************************************************/
1163
1164static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -05001165init_bios_area(void)
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001166{
1167 // init detected hardware BIOS Area
1168 // set 80x25 color (not clear from RBIL but usual)
1169 u16 eqf = GET_BDA(equipment_list_flags);
1170 SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1171
1172 // Just for the first int10 find its children
1173
1174 // the default char height
1175 SET_BDA(char_height, 0x10);
1176
1177 // Clear the screen
1178 SET_BDA(video_ctl, 0x60);
1179
1180 // Set the basic screen we have
1181 SET_BDA(video_switches, 0xf9);
1182
1183 // Set the basic modeset options
1184 SET_BDA(modeset_ctl, 0x51);
1185
1186 // Set the default MSR
1187 SET_BDA(video_msr, 0x09);
1188}
1189
Kevin O'Connor161d2012011-12-31 19:42:21 -05001190u16 VgaBDF VAR16;
1191
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001192void VISIBLE16
1193vga_post(struct bregs *regs)
1194{
1195 debug_enter(regs, DEBUG_VGA_POST);
1196
Kevin O'Connor161d2012011-12-31 19:42:21 -05001197 SET_VGA(VgaBDF, regs->ax);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001198
Kevin O'Connor161d2012011-12-31 19:42:21 -05001199 int ret = vgahw_init();
1200 if (ret) {
1201 dprintf(1, "Failed to initialize VGA hardware. Exiting.\n");
1202 return;
1203 }
Kevin O'Connor4c52fb42011-12-24 00:44:07 -05001204
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001205 init_bios_area();
1206
Kevin O'Connor161d2012011-12-31 19:42:21 -05001207 build_video_param();
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001208
1209 extern void entry_10(void);
Kevin O'Connor9f985422009-09-09 11:34:39 -04001210 SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001211
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001212 // XXX - clear screen and display info
1213
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001214 // Fixup checksum
1215 extern u8 _rom_header_size, _rom_header_checksum;
1216 SET_VGA(_rom_header_checksum, 0);
Kevin O'Connord113a992009-05-16 21:05:02 -04001217 u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
Kevin O'Connor1f2c3072009-05-06 23:35:59 -04001218 SET_VGA(_rom_header_checksum, sum);
1219}