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 // * extract hw code from framebuffer code
16 /****************************************************************
18 ****************************************************************/
21 memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
23 for (; lines; lines--, dst+=stride, src+=stride)
24 memcpy_far(seg, dst, seg, src, copylen);
29 memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
31 for (; lines; lines--, dst+=stride)
32 memset_far(seg, dst, val, setlen);
36 memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
38 for (; lines; lines--, dst+=stride)
39 memset16_far(seg, dst, val, setlen);
43 scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
44 , struct cursorpos ul, struct cursorpos lr)
46 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
47 u8 cheight = GET_GLOBAL(vparam_g->cheight);
48 int stride = GET_BDA(video_cols);
49 void *src_far, *dest_far;
51 dest_far = (void*)(ul.y * cheight * stride + ul.x);
52 src_far = dest_far + nblines * cheight * stride;
56 dest_far = (void*)(lr.y * cheight * stride + ul.x);
57 src_far = dest_far - nblines * cheight * stride;
60 int cols = lr.x - ul.x + 1;
61 int rows = lr.y - ul.y + 1;
63 outw(0x0105, VGAREG_GRDC_ADDRESS);
64 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
65 , (rows - nblines) * cheight);
69 outw(0x0205, VGAREG_GRDC_ADDRESS);
70 memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
71 outw(0x0005, VGAREG_GRDC_ADDRESS);
75 scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
76 , struct cursorpos ul, struct cursorpos lr)
78 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
79 u8 cheight = GET_GLOBAL(vparam_g->cheight);
80 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
81 int stride = GET_BDA(video_cols) * bpp;
82 void *src_far, *dest_far;
84 dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
85 src_far = dest_far + nblines * cheight * stride;
89 dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
90 src_far = dest_far - nblines * cheight * stride;
93 int cols = (lr.x - ul.x + 1) * bpp;
94 int rows = lr.y - ul.y + 1;
96 memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
97 , stride, (rows - nblines) * cheight / 2);
98 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
99 , stride, (rows - nblines) * cheight / 2);
103 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
104 , stride, nblines * cheight / 2);
105 memset_stride(SEG_CTEXT, dest_far, attr, cols
106 , stride, nblines * cheight / 2);
110 scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
111 , struct cursorpos ul, struct cursorpos lr)
113 u16 nbrows = GET_BDA(video_rows) + 1;
114 u16 nbcols = GET_BDA(video_cols);
115 void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
116 int stride = nbcols * 2;
118 dest_far += ul.y * stride + ul.x * 2;
119 src_far = dest_far + nblines * stride;
123 dest_far += lr.y * stride + ul.x * 2;
124 src_far = dest_far - nblines * stride;
127 int cols = (lr.x - ul.x + 1) * 2;
128 int rows = lr.y - ul.y + 1;
129 u16 seg = GET_GLOBAL(vmode_g->sstart);
131 dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
135 attr = (attr << 8) | ' ';
136 memset16_stride(seg, dest_far, attr, cols, stride, nblines);
140 vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
143 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
147 // FIXME gfx mode not complete
148 switch (GET_GLOBAL(vmode_g->memmodel)) {
151 scroll_text(vmode_g, nblines, attr, ul, lr);
155 scroll_pl4(vmode_g, nblines, attr, ul, lr);
158 scroll_cga(vmode_g, nblines, attr, ul, lr);
161 dprintf(1, "Scroll in graphics mode\n");
166 clear_screen(struct vgamode_s *vmode_g)
168 switch (GET_GLOBAL(vmode_g->memmodel)) {
171 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
174 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
177 outb(0x02, VGAREG_SEQU_ADDRESS);
178 u8 mmask = inb(VGAREG_SEQU_DATA);
179 outb(0x0f, VGAREG_SEQU_DATA); // all planes
180 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
181 outb(mmask, VGAREG_SEQU_DATA);
187 /****************************************************************
188 * Read/write characters to screen
189 ****************************************************************/
192 write_gfx_char_pl4(struct vgamode_s *vmode_g
193 , struct cursorpos cp, struct carattr ca)
195 u16 nbcols = GET_BDA(video_cols);
199 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
200 u8 cheight = GET_GLOBAL(vparam_g->cheight);
212 u16 addr = cp.x + cp.y * cheight * nbcols;
213 u16 src = ca.car * cheight;
214 outw(0x0f02, VGAREG_SEQU_ADDRESS);
215 outw(0x0205, VGAREG_GRDC_ADDRESS);
217 outw(0x1803, VGAREG_GRDC_ADDRESS);
219 outw(0x0003, VGAREG_GRDC_ADDRESS);
221 for (i = 0; i < cheight; i++) {
222 u8 *dest_far = (void*)(addr + i * nbcols);
224 for (j = 0; j < 8; j++) {
226 outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
227 GET_FARVAR(SEG_GRAPH, *dest_far);
228 if (GET_GLOBAL(fdata_g[src + i]) & mask)
229 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
231 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
234 outw(0xff08, VGAREG_GRDC_ADDRESS);
235 outw(0x0005, VGAREG_GRDC_ADDRESS);
236 outw(0x0003, VGAREG_GRDC_ADDRESS);
240 write_gfx_char_cga(struct vgamode_s *vmode_g
241 , struct cursorpos cp, struct carattr ca)
243 u16 nbcols = GET_BDA(video_cols);
247 u8 *fdata_g = vgafont8;
248 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
249 u16 addr = (cp.x * bpp) + cp.y * 320;
250 u16 src = ca.car * 8;
252 for (i = 0; i < 8; i++) {
253 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
260 data = GET_FARVAR(SEG_CTEXT, *dest_far);
262 for (j = 0; j < 8; j++) {
263 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
265 data ^= (ca.attr & 0x01) << (7 - j);
267 data |= (ca.attr & 0x01) << (7 - j);
271 SET_FARVAR(SEG_CTEXT, *dest_far, data);
276 data = GET_FARVAR(SEG_CTEXT, *dest_far);
278 for (j = 0; j < 4; j++) {
279 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
281 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
283 data |= (ca.attr & 0x03) << ((3 - j) * 2);
287 SET_FARVAR(SEG_CTEXT, *dest_far, data);
295 write_gfx_char_lin(struct vgamode_s *vmode_g
296 , struct cursorpos cp, struct carattr ca)
298 // Get the dimensions
299 u16 nbcols = GET_BDA(video_cols);
303 u8 *fdata_g = vgafont8;
304 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
305 u16 src = ca.car * 8;
307 for (i = 0; i < 8; i++) {
308 u8 *dest_far = (void*)(addr + i * nbcols * 8);
311 for (j = 0; j < 8; j++) {
313 if (GET_GLOBAL(fdata_g[src + i]) & mask)
315 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
322 write_text_char(struct vgamode_s *vmode_g
323 , struct cursorpos cp, struct carattr ca)
325 // Get the dimensions
326 u16 nbrows = GET_BDA(video_rows) + 1;
327 u16 nbcols = GET_BDA(video_cols);
329 // Compute the address
330 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
331 + (cp.x + cp.y * nbcols) * 2);
334 u16 dummy = (ca.attr << 8) | ca.car;
335 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
337 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
342 vgafb_write_char(struct cursorpos cp, struct carattr ca)
345 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
349 // FIXME gfx mode not complete
350 switch (GET_GLOBAL(vmode_g->memmodel)) {
353 write_text_char(vmode_g, cp, ca);
357 write_gfx_char_pl4(vmode_g, cp, ca);
360 write_gfx_char_cga(vmode_g, cp, ca);
363 write_gfx_char_lin(vmode_g, cp, ca);
369 vgafb_read_char(struct cursorpos cp)
372 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
376 if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
378 dprintf(1, "Read char in graphics mode\n");
382 // Get the dimensions
383 u16 nbrows = GET_BDA(video_rows) + 1;
384 u16 nbcols = GET_BDA(video_cols);
386 // Compute the address
387 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
388 + (cp.x + cp.y * nbcols) * 2);
389 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
390 struct carattr ca = {v, v>>8, 0};
394 struct carattr ca2 = {0, 0, 0};
399 /****************************************************************
401 ****************************************************************/
404 vgafb_write_pixel(u8 color, u16 x, u16 y)
407 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
410 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
413 u8 *addr_far, mask, attr, data;
414 switch (GET_GLOBAL(vmode_g->memmodel)) {
417 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
418 mask = 0x80 >> (x & 0x07);
419 outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
420 outw(0x0205, VGAREG_GRDC_ADDRESS);
421 data = GET_FARVAR(SEG_GRAPH, *addr_far);
423 outw(0x1803, VGAREG_GRDC_ADDRESS);
424 SET_FARVAR(SEG_GRAPH, *addr_far, color);
425 outw(0xff08, VGAREG_GRDC_ADDRESS);
426 outw(0x0005, VGAREG_GRDC_ADDRESS);
427 outw(0x0003, VGAREG_GRDC_ADDRESS);
430 if (GET_GLOBAL(vmode_g->pixbits) == 2)
431 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
433 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
436 data = GET_FARVAR(SEG_CTEXT, *addr_far);
437 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
438 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
439 mask = 0x03 << ((3 - (x & 0x03)) * 2);
441 attr = (color & 0x01) << (7 - (x & 0x07));
442 mask = 0x01 << (7 - (x & 0x07));
450 SET_FARVAR(SEG_CTEXT, *addr_far, data);
453 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
454 SET_FARVAR(SEG_GRAPH, *addr_far, color);
460 vgafb_read_pixel(u16 x, u16 y)
463 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
466 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
469 u8 *addr_far, mask, attr=0, data, i;
470 switch (GET_GLOBAL(vmode_g->memmodel)) {
473 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
474 mask = 0x80 >> (x & 0x07);
476 for (i = 0; i < 4; i++) {
477 outw((i << 8) | 0x04, VGAREG_GRDC_ADDRESS);
478 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
484 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
487 data = GET_FARVAR(SEG_CTEXT, *addr_far);
488 if (GET_GLOBAL(vmode_g->pixbits) == 2)
489 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
491 attr = (data >> (7 - (x & 0x07))) & 0x01;
494 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
495 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
502 /****************************************************************
504 ****************************************************************/
507 vgafb_load_font(u16 seg, void *src_far, u16 count
508 , u16 start, u8 destflags, u8 fontsize)
511 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
512 void *dest_far = (void*)(blockaddr + start*32);
514 for (i = 0; i < count; i++)
515 memcpy_far(SEG_GRAPH, dest_far + i*32
516 , seg, src_far + i*fontsize, fontsize);
517 release_font_access();