tizen 2.3.1 release
[external/qemu.git] / roms / seabios / vgasrc / vgafb.c
1 // Code for manipulating VGA framebuffers.
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 #include "vgabios.h" // vgafb_scroll
9 #include "biosvar.h" // GET_BDA
10 #include "util.h" // memset_far
11 #include "byteorder.h" // cpu_to_be16
12 #include "stdvga.h" // stdvga_planar4_plane
13
14
15 /****************************************************************
16  * Screen scrolling
17  ****************************************************************/
18
19 static inline void *
20 memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
21 {
22     for (; lines; lines--, dst+=stride, src+=stride)
23         memcpy_far(seg, dst, seg, src, copylen);
24     return dst;
25 }
26
27 static inline void
28 memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
29 {
30     for (; lines; lines--, dst+=stride)
31         memset_far(seg, dst, val, setlen);
32 }
33
34 static inline void
35 memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
36 {
37     for (; lines; lines--, dst+=stride)
38         memset16_far(seg, dst, val, setlen);
39 }
40
41 static void
42 scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
43            , struct cursorpos ul, struct cursorpos lr)
44 {
45     int cheight = GET_GLOBAL(vmode_g->cheight);
46     int cwidth = 1;
47     int stride = GET_BDA(video_cols) * cwidth;
48     void *src_far, *dest_far;
49     if (nblines >= 0) {
50         dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
51         src_far = dest_far + nblines * cheight * stride;
52     } else {
53         // Scroll down
54         nblines = -nblines;
55         dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
56         src_far = dest_far - nblines * cheight * stride;
57         stride = -stride;
58     }
59     if (attr < 0)
60         attr = 0;
61     int cols = lr.x - ul.x + 1;
62     int rows = lr.y - ul.y + 1;
63     int i;
64     for (i=0; i<4; i++) {
65         stdvga_planar4_plane(i);
66         void *dest = dest_far;
67         if (nblines < rows)
68             dest = memcpy_stride(SEG_GRAPH, dest, src_far, cols * cwidth
69                                  , stride, (rows - nblines) * cheight);
70         u8 pixels = (attr & (1<<i)) ? 0xff : 0x00;
71         memset_stride(SEG_GRAPH, dest, pixels, cols * cwidth
72                       , stride, nblines * cheight);
73     }
74     stdvga_planar4_plane(-1);
75 }
76
77 static void
78 scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
79             , struct cursorpos ul, struct cursorpos lr)
80 {
81     int cheight = GET_GLOBAL(vmode_g->cheight) / 2;
82     int cwidth = GET_GLOBAL(vmode_g->depth);
83     int stride = GET_BDA(video_cols) * cwidth;
84     void *src_far, *dest_far;
85     if (nblines >= 0) {
86         dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
87         src_far = dest_far + nblines * cheight * stride;
88     } else {
89         // Scroll down
90         nblines = -nblines;
91         dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
92         src_far = dest_far - nblines * cheight * stride;
93         stride = -stride;
94     }
95     if (attr < 0)
96         attr = 0;
97     if (cwidth == 1)
98         attr = (attr&1) | ((attr&1)<<1);
99     attr &= 3;
100     attr |= (attr<<2) | (attr<<4) | (attr<<6);
101     int cols = lr.x - ul.x + 1;
102     int rows = lr.y - ul.y + 1;
103     if (nblines < rows) {
104         memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth
105                       , stride, (rows - nblines) * cheight);
106         dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth
107                                  , stride, (rows - nblines) * cheight);
108     }
109     memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth
110                   , stride, nblines * cheight);
111     memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth
112                   , stride, nblines * cheight);
113 }
114
115 static void
116 scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr
117            , struct cursorpos ul, struct cursorpos lr)
118 {
119     int cheight = 8;
120     int cwidth = 8;
121     int stride = GET_BDA(video_cols) * cwidth;
122     void *src_far, *dest_far;
123     if (nblines >= 0) {
124         dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
125         src_far = dest_far + nblines * cheight * stride;
126     } else {
127         // Scroll down
128         nblines = -nblines;
129         dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
130         src_far = dest_far - nblines * cheight * stride;
131         stride = -stride;
132     }
133     if (attr < 0)
134         attr = 0;
135     int cols = lr.x - ul.x + 1;
136     int rows = lr.y - ul.y + 1;
137     if (nblines < rows)
138         dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols * cwidth
139                                  , stride, (rows - nblines) * cheight);
140     memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth
141                   , stride, nblines * cheight);
142 }
143
144 static void
145 scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
146             , struct cursorpos ul, struct cursorpos lr)
147 {
148     int cheight = 1;
149     int cwidth = 2;
150     int stride = GET_BDA(video_cols) * cwidth;
151     void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page);
152     if (nblines >= 0) {
153         dest_far += ul.y * cheight * stride + ul.x * cwidth;
154         src_far = dest_far + nblines * cheight * stride;
155     } else {
156         // Scroll down
157         nblines = -nblines;
158         dest_far += lr.y * cheight * stride + ul.x * cwidth;
159         src_far = dest_far - nblines * cheight * stride;
160         stride = -stride;
161     }
162     if (attr < 0)
163         attr = 0x07;
164     attr = (attr << 8) | ' ';
165     int cols = lr.x - ul.x + 1;
166     int rows = lr.y - ul.y + 1;
167     u16 seg = GET_GLOBAL(vmode_g->sstart);
168     if (nblines < rows)
169         dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth
170                                  , stride, (rows - nblines) * cheight);
171     memset16_stride(seg, dest_far, attr, cols * cwidth
172                     , stride, nblines * cheight);
173 }
174
175 void
176 vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
177 {
178     // Get the mode
179     struct vgamode_s *vmode_g = get_current_mode();
180     if (!vmode_g)
181         return;
182
183     // FIXME gfx mode not complete
184     switch (GET_GLOBAL(vmode_g->memmodel)) {
185     case MM_TEXT:
186         scroll_text(vmode_g, nblines, attr, ul, lr);
187         break;
188     case MM_PLANAR:
189         scroll_pl4(vmode_g, nblines, attr, ul, lr);
190         break;
191     case MM_CGA:
192         scroll_cga(vmode_g, nblines, attr, ul, lr);
193         break;
194     case MM_DIRECT:
195     case MM_PACKED:
196         scroll_lin(vmode_g, nblines, attr, ul, lr);
197         break;
198     default:
199         break;
200     }
201 }
202
203
204 /****************************************************************
205  * Read/write characters to screen
206  ****************************************************************/
207
208 static void
209 write_gfx_char_pl4(struct vgamode_s *vmode_g
210                    , struct cursorpos cp, struct carattr ca)
211 {
212     u16 nbcols = GET_BDA(video_cols);
213     if (cp.x >= nbcols)
214         return;
215
216     u8 cheight = GET_GLOBAL(vmode_g->cheight);
217     u8 *fdata_g;
218     switch (cheight) {
219     case 14:
220         fdata_g = vgafont14;
221         break;
222     case 16:
223         fdata_g = vgafont16;
224         break;
225     default:
226         fdata_g = vgafont8;
227     }
228     u16 addr = cp.x + cp.y * cheight * nbcols;
229     u16 src = ca.car * cheight;
230     int i;
231     for (i=0; i<4; i++) {
232         stdvga_planar4_plane(i);
233         u8 colors = ((ca.attr & (1<<i)) ? 0xff : 0x00);
234         int j;
235         for (j = 0; j < cheight; j++) {
236             u8 *dest_far = (void*)(addr + j * nbcols);
237             u8 pixels = colors & GET_GLOBAL(fdata_g[src + j]);
238             if (ca.attr & 0x80)
239                 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
240             SET_FARVAR(SEG_GRAPH, *dest_far, pixels);
241         }
242     }
243     stdvga_planar4_plane(-1);
244 }
245
246 static void
247 write_gfx_char_cga(struct vgamode_s *vmode_g
248                    , struct cursorpos cp, struct carattr ca)
249 {
250     u16 nbcols = GET_BDA(video_cols);
251     if (cp.x >= nbcols)
252         return;
253
254     u8 *fdata_g = vgafont8;
255     u8 bpp = GET_GLOBAL(vmode_g->depth);
256     u16 addr = (cp.x * bpp) + cp.y * 320;
257     u16 src = ca.car * 8;
258     u8 i;
259     for (i = 0; i < 8; i++) {
260         u8 *dest_far = (void*)(addr + (i >> 1) * 80);
261         if (i & 1)
262             dest_far += 0x2000;
263         if (bpp == 1) {
264             u8 colors = (ca.attr & 0x01) ? 0xff : 0x00;
265             u8 pixels = colors & GET_GLOBAL(fdata_g[src + i]);
266             if (ca.attr & 0x80)
267                 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
268             SET_FARVAR(SEG_CTEXT, *dest_far, pixels);
269         } else {
270             u16 pixels = 0;
271             u8 fontline = GET_GLOBAL(fdata_g[src + i]);
272             int j;
273             for (j = 0; j < 8; j++)
274                 if (fontline & (1<<j))
275                     pixels |= (ca.attr & 0x03) << (j*2);
276             pixels = cpu_to_be16(pixels);
277             if (ca.attr & 0x80)
278                 pixels ^= GET_FARVAR(SEG_GRAPH, *(u16*)dest_far);
279             SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, pixels);
280         }
281     }
282 }
283
284 static void
285 write_gfx_char_lin(struct vgamode_s *vmode_g
286                    , struct cursorpos cp, struct carattr ca)
287 {
288     // Get the dimensions
289     u16 nbcols = GET_BDA(video_cols);
290     if (cp.x >= nbcols)
291         return;
292
293     u8 *fdata_g = vgafont8;
294     u16 addr = cp.x * 8 + cp.y * nbcols * 64;
295     u16 src = ca.car * 8;
296     u8 i;
297     for (i = 0; i < 8; i++) {
298         u8 *dest_far = (void*)(addr + i * nbcols * 8);
299         u8 fontline = GET_GLOBAL(fdata_g[src + i]);
300         u8 j;
301         for (j = 0; j < 8; j++) {
302             u8 pixel = (fontline & (0x80>>j)) ? ca.attr : 0x00;
303             SET_FARVAR(SEG_GRAPH, dest_far[j], pixel);
304         }
305     }
306 }
307
308 static void
309 write_text_char(struct vgamode_s *vmode_g
310                 , struct cursorpos cp, struct carattr ca)
311 {
312     // Compute the address
313     u16 nbcols = GET_BDA(video_cols);
314     void *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
315                                 + (cp.x + cp.y * nbcols) * 2);
316
317     if (ca.use_attr) {
318         u16 dummy = (ca.attr << 8) | ca.car;
319         SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
320     } else {
321         SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
322     }
323 }
324
325 void
326 vgafb_write_char(struct cursorpos cp, struct carattr ca)
327 {
328     // Get the mode
329     struct vgamode_s *vmode_g = get_current_mode();
330     if (!vmode_g)
331         return;
332
333     // FIXME gfx mode not complete
334     switch (GET_GLOBAL(vmode_g->memmodel)) {
335     case MM_TEXT:
336         write_text_char(vmode_g, cp, ca);
337         break;
338     case MM_PLANAR:
339         write_gfx_char_pl4(vmode_g, cp, ca);
340         break;
341     case MM_CGA:
342         write_gfx_char_cga(vmode_g, cp, ca);
343         break;
344     case MM_DIRECT:
345     case MM_PACKED:
346         write_gfx_char_lin(vmode_g, cp, ca);
347         break;
348     default:
349         break;
350     }
351 }
352
353 struct carattr
354 vgafb_read_char(struct cursorpos cp)
355 {
356     // Get the mode
357     struct vgamode_s *vmode_g = get_current_mode();
358     if (!vmode_g)
359         goto fail;
360
361     if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
362         // FIXME gfx mode
363         dprintf(1, "Read char in graphics mode\n");
364         goto fail;
365     }
366
367     // Compute the address
368     u16 nbcols = GET_BDA(video_cols);
369     u16 *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
370                                + (cp.x + cp.y * nbcols) * 2);
371     u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
372     struct carattr ca = {v, v>>8, 0};
373     return ca;
374
375 fail: ;
376     struct carattr ca2 = {0, 0, 0};
377     return ca2;
378 }
379
380
381 /****************************************************************
382  * Read/write pixels
383  ****************************************************************/
384
385 void
386 vgafb_write_pixel(u8 color, u16 x, u16 y)
387 {
388     // Get the mode
389     struct vgamode_s *vmode_g = get_current_mode();
390     if (!vmode_g)
391         return;
392
393     u8 *addr_far, mask, attr, data, i;
394     switch (GET_GLOBAL(vmode_g->memmodel)) {
395     case MM_PLANAR:
396         addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
397         mask = 0x80 >> (x & 0x07);
398         for (i=0; i<4; i++) {
399             stdvga_planar4_plane(i);
400             u8 colors = (color & (1<<i)) ? 0xff : 0x00;
401             u8 orig = GET_FARVAR(SEG_GRAPH, *addr_far);
402             if (color & 0x80)
403                 colors ^= orig;
404             SET_FARVAR(SEG_GRAPH, *addr_far, (colors & mask) | (orig & ~mask));
405         }
406         stdvga_planar4_plane(-1);
407         break;
408     case MM_CGA:
409         if (GET_GLOBAL(vmode_g->depth) == 2)
410             addr_far = (void*)((x >> 2) + (y >> 1) * 80);
411         else
412             addr_far = (void*)((x >> 3) + (y >> 1) * 80);
413         if (y & 1)
414             addr_far += 0x2000;
415         data = GET_FARVAR(SEG_CTEXT, *addr_far);
416         if (GET_GLOBAL(vmode_g->depth) == 2) {
417             attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
418             mask = 0x03 << ((3 - (x & 0x03)) * 2);
419         } else {
420             attr = (color & 0x01) << (7 - (x & 0x07));
421             mask = 0x01 << (7 - (x & 0x07));
422         }
423         if (color & 0x80) {
424             data ^= attr;
425         } else {
426             data &= ~mask;
427             data |= attr;
428         }
429         SET_FARVAR(SEG_CTEXT, *addr_far, data);
430         break;
431     case MM_DIRECT:
432     case MM_PACKED:
433         addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
434         SET_FARVAR(SEG_GRAPH, *addr_far, color);
435         break;
436     default:
437     case MM_TEXT:
438         return;
439     }
440 }
441
442 u8
443 vgafb_read_pixel(u16 x, u16 y)
444 {
445     // Get the mode
446     struct vgamode_s *vmode_g = get_current_mode();
447     if (!vmode_g)
448         return 0;
449
450     u8 *addr_far, mask, attr=0, data, i;
451     switch (GET_GLOBAL(vmode_g->memmodel)) {
452     case MM_PLANAR:
453         addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
454         mask = 0x80 >> (x & 0x07);
455         attr = 0x00;
456         for (i = 0; i < 4; i++) {
457             stdvga_planar4_plane(i);
458             data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
459             if (data > 0)
460                 attr |= (0x01 << i);
461         }
462         stdvga_planar4_plane(-1);
463         break;
464     case MM_CGA:
465         addr_far = (void*)((x >> 2) + (y >> 1) * 80);
466         if (y & 1)
467             addr_far += 0x2000;
468         data = GET_FARVAR(SEG_CTEXT, *addr_far);
469         if (GET_GLOBAL(vmode_g->depth) == 2)
470             attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
471         else
472             attr = (data >> (7 - (x & 0x07))) & 0x01;
473         break;
474     case MM_DIRECT:
475     case MM_PACKED:
476         addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
477         attr = GET_FARVAR(SEG_GRAPH, *addr_far);
478         break;
479     default:
480     case MM_TEXT:
481         return 0;
482     }
483     return attr;
484 }