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 u8 cheight = GET_GLOBAL(vmode_g->cheight);
44 int stride = GET_BDA(video_cols);
45 void *src_far, *dest_far;
47 dest_far = (void*)(ul.y * cheight * stride + ul.x);
48 src_far = dest_far + nblines * cheight * stride;
52 dest_far = (void*)(lr.y * cheight * stride + ul.x);
53 src_far = dest_far - nblines * cheight * stride;
56 int cols = lr.x - ul.x + 1;
57 int rows = lr.y - ul.y + 1;
59 vgahw_grdc_write(0x05, 0x01);
60 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
61 , (rows - nblines) * cheight);
65 vgahw_grdc_write(0x05, 0x02);
66 memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
67 vgahw_grdc_write(0x05, 0x00);
71 scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
72 , struct cursorpos ul, struct cursorpos lr)
74 u8 cheight = GET_GLOBAL(vmode_g->cheight);
75 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
76 int stride = GET_BDA(video_cols) * bpp;
77 void *src_far, *dest_far;
79 dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
80 src_far = dest_far + nblines * cheight * stride;
84 dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
85 src_far = dest_far - nblines * cheight * stride;
88 int cols = (lr.x - ul.x + 1) * bpp;
89 int rows = lr.y - ul.y + 1;
91 memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
92 , stride, (rows - nblines) * cheight / 2);
93 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
94 , stride, (rows - nblines) * cheight / 2);
98 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
99 , stride, nblines * cheight / 2);
100 memset_stride(SEG_CTEXT, dest_far, attr, cols
101 , stride, nblines * cheight / 2);
105 scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
106 , struct cursorpos ul, struct cursorpos lr)
108 u16 nbrows = GET_BDA(video_rows) + 1;
109 u16 nbcols = GET_BDA(video_cols);
110 void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
111 int stride = nbcols * 2;
113 dest_far += ul.y * stride + ul.x * 2;
114 src_far = dest_far + nblines * stride;
118 dest_far += lr.y * stride + ul.x * 2;
119 src_far = dest_far - nblines * stride;
122 int cols = (lr.x - ul.x + 1) * 2;
123 int rows = lr.y - ul.y + 1;
124 u16 seg = GET_GLOBAL(vmode_g->sstart);
126 dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
130 attr = (attr << 8) | ' ';
131 memset16_stride(seg, dest_far, attr, cols, stride, nblines);
135 vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
138 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
142 // FIXME gfx mode not complete
143 switch (GET_GLOBAL(vmode_g->memmodel)) {
146 scroll_text(vmode_g, nblines, attr, ul, lr);
150 scroll_pl4(vmode_g, nblines, attr, ul, lr);
153 scroll_cga(vmode_g, nblines, attr, ul, lr);
156 dprintf(1, "Scroll in graphics mode\n");
161 clear_screen(struct vgamode_s *vmode_g)
163 switch (GET_GLOBAL(vmode_g->memmodel)) {
166 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
169 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
172 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
173 // but it should always be 0xf anyway.
174 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
179 /****************************************************************
180 * Read/write characters to screen
181 ****************************************************************/
184 write_gfx_char_pl4(struct vgamode_s *vmode_g
185 , struct cursorpos cp, struct carattr ca)
187 u16 nbcols = GET_BDA(video_cols);
191 u8 cheight = GET_GLOBAL(vmode_g->cheight);
203 u16 addr = cp.x + cp.y * cheight * nbcols;
204 u16 src = ca.car * cheight;
205 vgahw_sequ_write(0x02, 0x0f);
206 vgahw_grdc_write(0x05, 0x02);
208 vgahw_grdc_write(0x03, 0x18);
210 vgahw_grdc_write(0x03, 0x00);
212 for (i = 0; i < cheight; i++) {
213 u8 *dest_far = (void*)(addr + i * nbcols);
215 for (j = 0; j < 8; j++) {
217 vgahw_grdc_write(0x08, mask);
218 GET_FARVAR(SEG_GRAPH, *dest_far);
219 if (GET_GLOBAL(fdata_g[src + i]) & mask)
220 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
222 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
225 vgahw_grdc_write(0x08, 0xff);
226 vgahw_grdc_write(0x05, 0x00);
227 vgahw_grdc_write(0x03, 0x00);
231 write_gfx_char_cga(struct vgamode_s *vmode_g
232 , struct cursorpos cp, struct carattr ca)
234 u16 nbcols = GET_BDA(video_cols);
238 u8 *fdata_g = vgafont8;
239 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
240 u16 addr = (cp.x * bpp) + cp.y * 320;
241 u16 src = ca.car * 8;
243 for (i = 0; i < 8; i++) {
244 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
251 data = GET_FARVAR(SEG_CTEXT, *dest_far);
253 for (j = 0; j < 8; j++) {
254 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
256 data ^= (ca.attr & 0x01) << (7 - j);
258 data |= (ca.attr & 0x01) << (7 - j);
262 SET_FARVAR(SEG_CTEXT, *dest_far, data);
267 data = GET_FARVAR(SEG_CTEXT, *dest_far);
269 for (j = 0; j < 4; j++) {
270 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
272 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
274 data |= (ca.attr & 0x03) << ((3 - j) * 2);
278 SET_FARVAR(SEG_CTEXT, *dest_far, data);
286 write_gfx_char_lin(struct vgamode_s *vmode_g
287 , struct cursorpos cp, struct carattr ca)
289 // Get the dimensions
290 u16 nbcols = GET_BDA(video_cols);
294 u8 *fdata_g = vgafont8;
295 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
296 u16 src = ca.car * 8;
298 for (i = 0; i < 8; i++) {
299 u8 *dest_far = (void*)(addr + i * nbcols * 8);
302 for (j = 0; j < 8; j++) {
304 if (GET_GLOBAL(fdata_g[src + i]) & mask)
306 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
313 write_text_char(struct vgamode_s *vmode_g
314 , struct cursorpos cp, struct carattr ca)
316 // Get the dimensions
317 u16 nbrows = GET_BDA(video_rows) + 1;
318 u16 nbcols = GET_BDA(video_cols);
320 // Compute the address
321 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
322 + (cp.x + cp.y * nbcols) * 2);
325 u16 dummy = (ca.attr << 8) | ca.car;
326 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
328 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
333 vgafb_write_char(struct cursorpos cp, struct carattr ca)
336 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
340 // FIXME gfx mode not complete
341 switch (GET_GLOBAL(vmode_g->memmodel)) {
344 write_text_char(vmode_g, cp, ca);
348 write_gfx_char_pl4(vmode_g, cp, ca);
351 write_gfx_char_cga(vmode_g, cp, ca);
354 write_gfx_char_lin(vmode_g, cp, ca);
360 vgafb_read_char(struct cursorpos cp)
363 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
367 if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
369 dprintf(1, "Read char in graphics mode\n");
373 // Get the dimensions
374 u16 nbrows = GET_BDA(video_rows) + 1;
375 u16 nbcols = GET_BDA(video_cols);
377 // Compute the address
378 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
379 + (cp.x + cp.y * nbcols) * 2);
380 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
381 struct carattr ca = {v, v>>8, 0};
385 struct carattr ca2 = {0, 0, 0};
390 /****************************************************************
392 ****************************************************************/
395 vgafb_write_pixel(u8 color, u16 x, u16 y)
398 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
401 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
404 u8 *addr_far, mask, attr, data;
405 switch (GET_GLOBAL(vmode_g->memmodel)) {
408 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
409 mask = 0x80 >> (x & 0x07);
410 vgahw_grdc_write(0x08, mask);
411 vgahw_grdc_write(0x05, 0x02);
412 data = GET_FARVAR(SEG_GRAPH, *addr_far);
414 vgahw_grdc_write(0x03, 0x18);
415 SET_FARVAR(SEG_GRAPH, *addr_far, color);
416 vgahw_grdc_write(0x08, 0xff);
417 vgahw_grdc_write(0x05, 0x00);
418 vgahw_grdc_write(0x03, 0x00);
421 if (GET_GLOBAL(vmode_g->pixbits) == 2)
422 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
424 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
427 data = GET_FARVAR(SEG_CTEXT, *addr_far);
428 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
429 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
430 mask = 0x03 << ((3 - (x & 0x03)) * 2);
432 attr = (color & 0x01) << (7 - (x & 0x07));
433 mask = 0x01 << (7 - (x & 0x07));
441 SET_FARVAR(SEG_CTEXT, *addr_far, data);
444 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
445 SET_FARVAR(SEG_GRAPH, *addr_far, color);
451 vgafb_read_pixel(u16 x, u16 y)
454 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
457 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
460 u8 *addr_far, mask, attr=0, data, i;
461 switch (GET_GLOBAL(vmode_g->memmodel)) {
464 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
465 mask = 0x80 >> (x & 0x07);
467 for (i = 0; i < 4; i++) {
468 vgahw_grdc_write(0x04, i);
469 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
475 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
478 data = GET_FARVAR(SEG_CTEXT, *addr_far);
479 if (GET_GLOBAL(vmode_g->pixbits) == 2)
480 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
482 attr = (data >> (7 - (x & 0x07))) & 0x01;
485 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
486 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
493 /****************************************************************
495 ****************************************************************/
498 vgafb_load_font(u16 seg, void *src_far, u16 count
499 , u16 start, u8 destflags, u8 fontsize)
502 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
503 void *dest_far = (void*)(blockaddr + start*32);
505 for (i = 0; i < count; i++)
506 memcpy_far(SEG_GRAPH, dest_far + i*32
507 , seg, src_far + i*fontsize, fontsize);
508 release_font_access();