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
14 memcpy16_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
16 memcpy_far(d_seg, d_far, s_seg, s_far, len);
20 /****************************************************************
22 ****************************************************************/
25 vgamem_copy_pl4(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
28 u16 src = ysrc * cheight * nbcols + xstart;
29 u16 dest = ydest * cheight * nbcols + xstart;
30 outw(0x0105, VGAREG_GRDC_ADDRESS);
32 for (i = 0; i < cheight; i++)
33 memcpy_far(SEG_GRAPH, (void*)(dest + i * nbcols)
34 , SEG_GRAPH, (void*)(src + i * nbcols), cols);
35 outw(0x0005, VGAREG_GRDC_ADDRESS);
39 vgamem_fill_pl4(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
42 u16 dest = ystart * cheight * nbcols + xstart;
43 outw(0x0205, VGAREG_GRDC_ADDRESS);
45 for (i = 0; i < cheight; i++)
46 memset_far(SEG_GRAPH, (void*)(dest + i * nbcols), attr, cols);
47 outw(0x0005, VGAREG_GRDC_ADDRESS);
51 vgamem_copy_cga(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
54 u16 src = ((ysrc * cheight * nbcols) >> 1) + xstart;
55 u16 dest = ((ydest * cheight * nbcols) >> 1) + xstart;
57 for (i = 0; i < cheight; i++)
59 memcpy_far(SEG_CTEXT, (void*)(0x2000 + dest + (i >> 1) * nbcols)
60 , SEG_CTEXT, (void*)(0x2000 + src + (i >> 1) * nbcols)
63 memcpy_far(SEG_CTEXT, (void*)(dest + (i >> 1) * nbcols)
64 , SEG_CTEXT, (void*)(src + (i >> 1) * nbcols), cols);
68 vgamem_fill_cga(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
71 u16 dest = ((ystart * cheight * nbcols) >> 1) + xstart;
73 for (i = 0; i < cheight; i++)
75 memset_far(SEG_CTEXT, (void*)(0x2000 + dest + (i >> 1) * nbcols)
78 memset_far(SEG_CTEXT, (void*)(dest + (i >> 1) * nbcols), attr, cols);
82 biosfn_scroll(u8 nblines, u8 attr, u8 rul, u8 cul, u8 rlr, u8 clr, u8 page,
85 // page == 0xFF if current
92 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
97 u16 nbrows = GET_BDA(video_rows) + 1;
98 u16 nbcols = GET_BDA(video_cols);
100 // Get the current page
102 page = GET_BDA(video_page);
108 if (nblines > nbrows)
110 u8 cols = clr - cul + 1;
112 if (GET_GLOBAL(vmode_g->class) == TEXT) {
113 // Compute the address
114 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page));
115 dprintf(3, "Scroll, address %p (%d %d %02x)\n"
116 , address_far, nbrows, nbcols, page);
118 if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
119 && clr == nbcols - 1) {
120 memset16_far(GET_GLOBAL(vmode_g->sstart), address_far
121 , (u16)attr * 0x100 + ' ', nbrows * nbcols * 2);
122 } else { // if Scroll up
123 if (dir == SCROLL_UP) {
125 for (i = rul; i <= rlr; i++)
126 if ((i + nblines > rlr) || (nblines == 0))
127 memset16_far(GET_GLOBAL(vmode_g->sstart)
128 , address_far + (i * nbcols + cul) * 2
129 , (u16)attr * 0x100 + ' ', cols * 2);
131 memcpy16_far(GET_GLOBAL(vmode_g->sstart)
132 , address_far + (i * nbcols + cul) * 2
133 , GET_GLOBAL(vmode_g->sstart)
134 , (void*)(((i + nblines) * nbcols + cul) * 2)
138 for (i = rlr; i >= rul; i--) {
139 if ((i < rul + nblines) || (nblines == 0))
140 memset16_far(GET_GLOBAL(vmode_g->sstart)
141 , address_far + (i * nbcols + cul) * 2
142 , (u16)attr * 0x100 + ' ', cols * 2);
144 memcpy16_far(GET_GLOBAL(vmode_g->sstart)
145 , address_far + (i * nbcols + cul) * 2
146 , GET_GLOBAL(vmode_g->sstart)
147 , (void*)(((i - nblines) * nbcols + cul) * 2)
157 // FIXME gfx mode not complete
158 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
159 u8 cheight = GET_GLOBAL(vparam_g->cheight);
160 switch (GET_GLOBAL(vmode_g->memmodel)) {
163 if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
164 && clr == nbcols - 1) {
165 outw(0x0205, VGAREG_GRDC_ADDRESS);
166 memset_far(GET_GLOBAL(vmode_g->sstart), 0, attr,
167 nbrows * nbcols * cheight);
168 outw(0x0005, VGAREG_GRDC_ADDRESS);
169 } else { // if Scroll up
170 if (dir == SCROLL_UP) {
172 for (i = rul; i <= rlr; i++)
173 if ((i + nblines > rlr) || (nblines == 0))
174 vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
177 vgamem_copy_pl4(cul, i + nblines, i, cols,
181 for (i = rlr; i >= rul; i--) {
182 if ((i < rul + nblines) || (nblines == 0))
183 vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
186 vgamem_copy_pl4(cul, i, i - nblines, cols,
195 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
196 if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
197 && clr == nbcols - 1) {
198 memset_far(GET_GLOBAL(vmode_g->sstart), 0, attr,
199 nbrows * nbcols * cheight * bpp);
207 if (dir == SCROLL_UP) {
209 for (i = rul; i <= rlr; i++)
210 if ((i + nblines > rlr) || (nblines == 0))
211 vgamem_fill_cga(cul, i, cols, nbcols, cheight,
214 vgamem_copy_cga(cul, i + nblines, i, cols,
218 for (i = rlr; i >= rul; i--) {
219 if ((i < rul + nblines) || (nblines == 0))
220 vgamem_fill_cga(cul, i, cols, nbcols, cheight,
223 vgamem_copy_cga(cul, i, i - nblines, cols,
233 dprintf(1, "Scroll in graphics mode\n");
238 /****************************************************************
239 * Read/write characters to screen
240 ****************************************************************/
243 write_gfx_char_pl4(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols,
257 u16 addr = xcurs + ycurs * cheight * nbcols;
258 u16 src = car * cheight;
259 outw(0x0f02, VGAREG_SEQU_ADDRESS);
260 outw(0x0205, VGAREG_GRDC_ADDRESS);
262 outw(0x1803, VGAREG_GRDC_ADDRESS);
264 outw(0x0003, VGAREG_GRDC_ADDRESS);
266 for (i = 0; i < cheight; i++) {
267 u8 *dest_far = (void*)(addr + i * nbcols);
269 for (j = 0; j < 8; j++) {
271 outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
272 GET_FARVAR(SEG_GRAPH, *dest_far);
273 if (GET_GLOBAL(fdata_g[src + i]) & mask)
274 SET_FARVAR(SEG_GRAPH, *dest_far, attr & 0x0f);
276 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
279 outw(0xff08, VGAREG_GRDC_ADDRESS);
280 outw(0x0005, VGAREG_GRDC_ADDRESS);
281 outw(0x0003, VGAREG_GRDC_ADDRESS);
285 write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
287 u8 *fdata_g = vgafont8;
288 u16 addr = (xcurs * bpp) + ycurs * 320;
291 for (i = 0; i < 8; i++) {
292 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
299 data = GET_FARVAR(SEG_CTEXT, *dest_far);
301 for (j = 0; j < 8; j++) {
302 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
304 data ^= (attr & 0x01) << (7 - j);
306 data |= (attr & 0x01) << (7 - j);
310 SET_FARVAR(SEG_CTEXT, *dest_far, data);
315 data = GET_FARVAR(SEG_CTEXT, *dest_far);
317 for (j = 0; j < 4; j++) {
318 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
320 data ^= (attr & 0x03) << ((3 - j) * 2);
322 data |= (attr & 0x03) << ((3 - j) * 2);
326 SET_FARVAR(SEG_CTEXT, *dest_far, data);
334 write_gfx_char_lin(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols)
336 u8 *fdata_g = vgafont8;
337 u16 addr = xcurs * 8 + ycurs * nbcols * 64;
340 for (i = 0; i < 8; i++) {
341 u8 *dest_far = (void*)(addr + i * nbcols * 8);
344 for (j = 0; j < 8; j++) {
346 if (GET_GLOBAL(fdata_g[src + i]) & mask)
348 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
355 biosfn_write_char_attr(u8 car, u8 page, u8 attr, u16 count)
358 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
362 // Get the cursor pos for the page
363 u16 cursor = biosfn_get_cursor_pos(page);
364 u8 xcurs = cursor & 0x00ff;
365 u8 ycurs = (cursor & 0xff00) >> 8;
367 // Get the dimensions
368 u16 nbrows = GET_BDA(video_rows) + 1;
369 u16 nbcols = GET_BDA(video_cols);
371 if (GET_GLOBAL(vmode_g->class) == TEXT) {
372 // Compute the address
373 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
374 + (xcurs + ycurs * nbcols) * 2);
376 u16 dummy = ((u16)attr << 8) + car;
377 memset16_far(GET_GLOBAL(vmode_g->sstart), address_far, dummy, count * 2);
381 // FIXME gfx mode not complete
382 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
383 u8 cheight = GET_GLOBAL(vparam_g->cheight);
384 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
385 while ((count-- > 0) && (xcurs < nbcols)) {
386 switch (GET_GLOBAL(vmode_g->memmodel)) {
389 write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols, cheight);
392 write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
395 write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
403 biosfn_write_char_only(u8 car, u8 page, u8 attr, u16 count)
406 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
410 // Get the cursor pos for the page
411 u16 cursor = biosfn_get_cursor_pos(page);
412 u8 xcurs = cursor & 0x00ff;
413 u8 ycurs = (cursor & 0xff00) >> 8;
415 // Get the dimensions
416 u16 nbrows = GET_BDA(video_rows) + 1;
417 u16 nbcols = GET_BDA(video_cols);
419 if (GET_GLOBAL(vmode_g->class) == TEXT) {
420 // Compute the address
421 u8 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
422 + (xcurs + ycurs * nbcols) * 2);
423 while (count-- > 0) {
424 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far, car);
430 // FIXME gfx mode not complete
431 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
432 u8 cheight = GET_GLOBAL(vparam_g->cheight);
433 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
434 while ((count-- > 0) && (xcurs < nbcols)) {
435 switch (GET_GLOBAL(vmode_g->memmodel)) {
438 write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols, cheight);
441 write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
444 write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
452 biosfn_read_char_attr(u8 page, u16 *car)
455 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
459 // Get the cursor pos for the page
460 u16 cursor = biosfn_get_cursor_pos(page);
461 u8 xcurs = cursor & 0x00ff;
462 u8 ycurs = (cursor & 0xff00) >> 8;
464 // Get the dimensions
465 u16 nbrows = GET_BDA(video_rows) + 1;
466 u16 nbcols = GET_BDA(video_cols);
468 if (GET_GLOBAL(vmode_g->class) == TEXT) {
469 // Compute the address
470 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
471 + (xcurs + ycurs * nbcols) * 2);
473 *car = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
476 dprintf(1, "Read char in graphics mode\n");
481 /****************************************************************
483 ****************************************************************/
486 biosfn_write_pixel(u8 BH, u8 AL, u16 CX, u16 DX)
489 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
492 if (GET_GLOBAL(vmode_g->class) == TEXT)
495 u8 *addr_far, mask, attr, data;
496 switch (GET_GLOBAL(vmode_g->memmodel)) {
499 addr_far = (void*)(CX / 8 + DX * GET_BDA(video_cols));
500 mask = 0x80 >> (CX & 0x07);
501 outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
502 outw(0x0205, VGAREG_GRDC_ADDRESS);
503 data = GET_FARVAR(SEG_GRAPH, *addr_far);
505 outw(0x1803, VGAREG_GRDC_ADDRESS);
506 SET_FARVAR(SEG_GRAPH, *addr_far, AL);
507 outw(0xff08, VGAREG_GRDC_ADDRESS);
508 outw(0x0005, VGAREG_GRDC_ADDRESS);
509 outw(0x0003, VGAREG_GRDC_ADDRESS);
512 if (GET_GLOBAL(vmode_g->pixbits) == 2)
513 addr_far = (void*)((CX >> 2) + (DX >> 1) * 80);
515 addr_far = (void*)((CX >> 3) + (DX >> 1) * 80);
518 data = GET_FARVAR(SEG_CTEXT, *addr_far);
519 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
520 attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
521 mask = 0x03 << ((3 - (CX & 0x03)) * 2);
523 attr = (AL & 0x01) << (7 - (CX & 0x07));
524 mask = 0x01 << (7 - (CX & 0x07));
532 SET_FARVAR(SEG_CTEXT, *addr_far, data);
535 addr_far = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
536 SET_FARVAR(SEG_GRAPH, *addr_far, AL);
542 biosfn_read_pixel(u8 BH, u16 CX, u16 DX, u16 *AX)
545 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
548 if (GET_GLOBAL(vmode_g->class) == TEXT)
551 u8 *addr_far, mask, attr=0, data, i;
552 switch (GET_GLOBAL(vmode_g->memmodel)) {
555 addr_far = (void*)(CX / 8 + DX * GET_BDA(video_cols));
556 mask = 0x80 >> (CX & 0x07);
558 for (i = 0; i < 4; i++) {
559 outw((i << 8) | 0x04, VGAREG_GRDC_ADDRESS);
560 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
566 addr_far = (void*)((CX >> 2) + (DX >> 1) * 80);
569 data = GET_FARVAR(SEG_CTEXT, *addr_far);
570 if (GET_GLOBAL(vmode_g->pixbits) == 2)
571 attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
573 attr = (data >> (7 - (CX & 0x07))) & 0x01;
576 addr_far = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
577 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
580 *AX = (*AX & 0xff00) | attr;
584 /****************************************************************
586 ****************************************************************/
589 biosfn_load_text_user_pat(u16 ES, u16 BP, u16 CX, u16 DX, u8 BL, u8 BH)
592 u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
594 for (i = 0; i < CX; i++) {
595 void *src_far = (void*)(BP + i * BH);
596 void *dest_far = (void*)(blockaddr + (DX + i) * 32);
597 memcpy_far(SEG_GRAPH, dest_far, ES, src_far, BH);
599 release_font_access();
603 biosfn_load_text_8_14_pat(u8 BL)
606 u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
608 for (i = 0; i < 0x100; i++) {
610 void *dest_far = (void*)(blockaddr + i * 32);
611 memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont14[src], 14);
613 release_font_access();
617 biosfn_load_text_8_8_pat(u8 BL)
620 u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
622 for (i = 0; i < 0x100; i++) {
624 void *dest_far = (void*)(blockaddr + i * 32);
625 memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont8[src], 8);
627 release_font_access();
631 biosfn_load_text_8_16_pat(u8 BL)
634 u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
636 for (i = 0; i < 0x100; i++) {
638 void *dest_far = (void*)(blockaddr + i * 32);
639 memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont16[src], 16);
641 release_font_access();