1 // Code for manipulating VGA framebuffers.
3 // Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
8 #include "biosvar.h" // GET_BDA
9 #include "util.h" // memset_far
10 #include "vgatables.h" // find_vga_entry
13 /****************************************************************
15 ****************************************************************/
18 memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
20 for (; lines; lines--, dst+=stride, src+=stride)
21 memcpy_far(seg, dst, seg, src, copylen);
26 memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
28 for (; lines; lines--, dst+=stride)
29 memset_far(seg, dst, val, setlen);
33 memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
35 for (; lines; lines--, dst+=stride)
36 memset16_far(seg, dst, val, setlen);
40 scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
41 , struct cursorpos ul, struct cursorpos lr)
43 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
44 u8 cheight = GET_GLOBAL(vparam_g->cheight);
45 int stride = GET_BDA(video_cols);
46 void *src_far, *dest_far;
48 dest_far = (void*)(ul.y * cheight * stride + ul.x);
49 src_far = dest_far + nblines * cheight * stride;
53 dest_far = (void*)(lr.y * cheight * stride + ul.x);
54 src_far = dest_far - nblines * cheight * stride;
57 int cols = lr.x - ul.x + 1;
58 int rows = lr.y - ul.y + 1;
60 vgahw_grdc_write(0x05, 0x01);
61 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
62 , (rows - nblines) * cheight);
66 vgahw_grdc_write(0x05, 0x02);
67 memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
68 vgahw_grdc_write(0x05, 0x00);
72 scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
73 , struct cursorpos ul, struct cursorpos lr)
75 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
76 u8 cheight = GET_GLOBAL(vparam_g->cheight);
77 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
78 int stride = GET_BDA(video_cols) * bpp;
79 void *src_far, *dest_far;
81 dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
82 src_far = dest_far + nblines * cheight * stride;
86 dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
87 src_far = dest_far - nblines * cheight * stride;
90 int cols = (lr.x - ul.x + 1) * bpp;
91 int rows = lr.y - ul.y + 1;
93 memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
94 , stride, (rows - nblines) * cheight / 2);
95 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
96 , stride, (rows - nblines) * cheight / 2);
100 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
101 , stride, nblines * cheight / 2);
102 memset_stride(SEG_CTEXT, dest_far, attr, cols
103 , stride, nblines * cheight / 2);
107 scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
108 , struct cursorpos ul, struct cursorpos lr)
110 u16 nbrows = GET_BDA(video_rows) + 1;
111 u16 nbcols = GET_BDA(video_cols);
112 void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
113 int stride = nbcols * 2;
115 dest_far += ul.y * stride + ul.x * 2;
116 src_far = dest_far + nblines * stride;
120 dest_far += lr.y * stride + ul.x * 2;
121 src_far = dest_far - nblines * stride;
124 int cols = (lr.x - ul.x + 1) * 2;
125 int rows = lr.y - ul.y + 1;
126 u16 seg = GET_GLOBAL(vmode_g->sstart);
128 dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
132 attr = (attr << 8) | ' ';
133 memset16_stride(seg, dest_far, attr, cols, stride, nblines);
137 vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
140 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
144 // FIXME gfx mode not complete
145 switch (GET_GLOBAL(vmode_g->memmodel)) {
148 scroll_text(vmode_g, nblines, attr, ul, lr);
152 scroll_pl4(vmode_g, nblines, attr, ul, lr);
155 scroll_cga(vmode_g, nblines, attr, ul, lr);
158 dprintf(1, "Scroll in graphics mode\n");
163 clear_screen(struct vgamode_s *vmode_g)
165 switch (GET_GLOBAL(vmode_g->memmodel)) {
168 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
171 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
174 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
175 // but it should always be 0xf anyway.
176 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
181 /****************************************************************
182 * Read/write characters to screen
183 ****************************************************************/
186 write_gfx_char_pl4(struct vgamode_s *vmode_g
187 , struct cursorpos cp, struct carattr ca)
189 u16 nbcols = GET_BDA(video_cols);
193 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
194 u8 cheight = GET_GLOBAL(vparam_g->cheight);
206 u16 addr = cp.x + cp.y * cheight * nbcols;
207 u16 src = ca.car * cheight;
208 vgahw_sequ_write(0x02, 0x0f);
209 vgahw_grdc_write(0x05, 0x02);
211 vgahw_grdc_write(0x03, 0x18);
213 vgahw_grdc_write(0x03, 0x00);
215 for (i = 0; i < cheight; i++) {
216 u8 *dest_far = (void*)(addr + i * nbcols);
218 for (j = 0; j < 8; j++) {
220 vgahw_grdc_write(0x08, mask);
221 GET_FARVAR(SEG_GRAPH, *dest_far);
222 if (GET_GLOBAL(fdata_g[src + i]) & mask)
223 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
225 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
228 vgahw_grdc_write(0x08, 0xff);
229 vgahw_grdc_write(0x05, 0x00);
230 vgahw_grdc_write(0x03, 0x00);
234 write_gfx_char_cga(struct vgamode_s *vmode_g
235 , struct cursorpos cp, struct carattr ca)
237 u16 nbcols = GET_BDA(video_cols);
241 u8 *fdata_g = vgafont8;
242 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
243 u16 addr = (cp.x * bpp) + cp.y * 320;
244 u16 src = ca.car * 8;
246 for (i = 0; i < 8; i++) {
247 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
254 data = GET_FARVAR(SEG_CTEXT, *dest_far);
256 for (j = 0; j < 8; j++) {
257 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
259 data ^= (ca.attr & 0x01) << (7 - j);
261 data |= (ca.attr & 0x01) << (7 - j);
265 SET_FARVAR(SEG_CTEXT, *dest_far, data);
270 data = GET_FARVAR(SEG_CTEXT, *dest_far);
272 for (j = 0; j < 4; j++) {
273 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
275 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
277 data |= (ca.attr & 0x03) << ((3 - j) * 2);
281 SET_FARVAR(SEG_CTEXT, *dest_far, data);
289 write_gfx_char_lin(struct vgamode_s *vmode_g
290 , struct cursorpos cp, struct carattr ca)
292 // Get the dimensions
293 u16 nbcols = GET_BDA(video_cols);
297 u8 *fdata_g = vgafont8;
298 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
299 u16 src = ca.car * 8;
301 for (i = 0; i < 8; i++) {
302 u8 *dest_far = (void*)(addr + i * nbcols * 8);
305 for (j = 0; j < 8; j++) {
307 if (GET_GLOBAL(fdata_g[src + i]) & mask)
309 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
316 write_text_char(struct vgamode_s *vmode_g
317 , struct cursorpos cp, struct carattr ca)
319 // Get the dimensions
320 u16 nbrows = GET_BDA(video_rows) + 1;
321 u16 nbcols = GET_BDA(video_cols);
323 // Compute the address
324 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
325 + (cp.x + cp.y * nbcols) * 2);
328 u16 dummy = (ca.attr << 8) | ca.car;
329 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
331 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
336 vgafb_write_char(struct cursorpos cp, struct carattr ca)
339 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
343 // FIXME gfx mode not complete
344 switch (GET_GLOBAL(vmode_g->memmodel)) {
347 write_text_char(vmode_g, cp, ca);
351 write_gfx_char_pl4(vmode_g, cp, ca);
354 write_gfx_char_cga(vmode_g, cp, ca);
357 write_gfx_char_lin(vmode_g, cp, ca);
363 vgafb_read_char(struct cursorpos cp)
366 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
370 if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
372 dprintf(1, "Read char in graphics mode\n");
376 // Get the dimensions
377 u16 nbrows = GET_BDA(video_rows) + 1;
378 u16 nbcols = GET_BDA(video_cols);
380 // Compute the address
381 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
382 + (cp.x + cp.y * nbcols) * 2);
383 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
384 struct carattr ca = {v, v>>8, 0};
388 struct carattr ca2 = {0, 0, 0};
393 /****************************************************************
395 ****************************************************************/
398 vgafb_write_pixel(u8 color, u16 x, u16 y)
401 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
404 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
407 u8 *addr_far, mask, attr, data;
408 switch (GET_GLOBAL(vmode_g->memmodel)) {
411 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
412 mask = 0x80 >> (x & 0x07);
413 vgahw_grdc_write(0x08, mask);
414 vgahw_grdc_write(0x05, 0x02);
415 data = GET_FARVAR(SEG_GRAPH, *addr_far);
417 vgahw_grdc_write(0x03, 0x18);
418 SET_FARVAR(SEG_GRAPH, *addr_far, color);
419 vgahw_grdc_write(0x08, 0xff);
420 vgahw_grdc_write(0x05, 0x00);
421 vgahw_grdc_write(0x03, 0x00);
424 if (GET_GLOBAL(vmode_g->pixbits) == 2)
425 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
427 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
430 data = GET_FARVAR(SEG_CTEXT, *addr_far);
431 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
432 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
433 mask = 0x03 << ((3 - (x & 0x03)) * 2);
435 attr = (color & 0x01) << (7 - (x & 0x07));
436 mask = 0x01 << (7 - (x & 0x07));
444 SET_FARVAR(SEG_CTEXT, *addr_far, data);
447 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
448 SET_FARVAR(SEG_GRAPH, *addr_far, color);
454 vgafb_read_pixel(u16 x, u16 y)
457 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
460 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
463 u8 *addr_far, mask, attr=0, data, i;
464 switch (GET_GLOBAL(vmode_g->memmodel)) {
467 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
468 mask = 0x80 >> (x & 0x07);
470 for (i = 0; i < 4; i++) {
471 vgahw_grdc_write(0x04, i);
472 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
478 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
481 data = GET_FARVAR(SEG_CTEXT, *addr_far);
482 if (GET_GLOBAL(vmode_g->pixbits) == 2)
483 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
485 attr = (data >> (7 - (x & 0x07))) & 0x01;
488 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
489 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
496 /****************************************************************
498 ****************************************************************/
501 vgafb_load_font(u16 seg, void *src_far, u16 count
502 , u16 start, u8 destflags, u8 fontsize)
505 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
506 void *dest_far = (void*)(blockaddr + start*32);
508 for (i = 0; i < count; i++)
509 memcpy_far(SEG_GRAPH, dest_far + i*32
510 , seg, src_far + i*fontsize, fontsize);
511 release_font_access();