blob: 3b2f367fb083ac9daa554a8f0bfcd65171fc1824 [file] [log] [blame]
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001// 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
Kevin O'Connorf98bbf02012-01-27 23:09:02 -05008#include "vgabios.h" // vgafb_scroll
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04009#include "biosvar.h" // GET_BDA
10#include "util.h" // memset_far
Kevin O'Connorb3064592012-08-14 21:20:10 -040011#include "byteorder.h" // cpu_to_be16
Kevin O'Connor160d34a2012-01-16 18:48:26 -050012#include "stdvga.h" // stdvga_planar4_plane
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040013
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040014
15/****************************************************************
16 * Screen scrolling
17 ****************************************************************/
18
Kevin O'Connor2c34f412009-05-31 15:25:14 -040019static inline void *
20memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040021{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040022 for (; lines; lines--, dst+=stride, src+=stride)
23 memcpy_far(seg, dst, seg, src, copylen);
24 return dst;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040025}
26
Kevin O'Connor2c34f412009-05-31 15:25:14 -040027static inline void
28memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040029{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040030 for (; lines; lines--, dst+=stride)
31 memset_far(seg, dst, val, setlen);
32}
33
34static inline void
35memset16_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);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040039}
40
41static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040042scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
43 , struct cursorpos ul, struct cursorpos lr)
44{
Kevin O'Connor68ab0412012-01-01 10:54:19 -050045 int cheight = GET_GLOBAL(vmode_g->cheight);
46 int cwidth = 1;
47 int stride = GET_BDA(video_cols) * cwidth;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040048 void *src_far, *dest_far;
49 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050050 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040051 src_far = dest_far + nblines * cheight * stride;
52 } else {
53 // Scroll down
54 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050055 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040056 src_far = dest_far - nblines * cheight * stride;
57 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040058 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040059 if (attr < 0)
60 attr = 0;
Kevin O'Connor160d34a2012-01-16 18:48:26 -050061 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);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040075}
76
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040077static void
78scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
79 , struct cursorpos ul, struct cursorpos lr)
80{
Kevin O'Connor68ab0412012-01-01 10:54:19 -050081 int cheight = GET_GLOBAL(vmode_g->cheight) / 2;
Kevin O'Connor80da87d2012-01-02 11:13:14 -050082 int cwidth = GET_GLOBAL(vmode_g->depth);
Kevin O'Connor68ab0412012-01-01 10:54:19 -050083 int stride = GET_BDA(video_cols) * cwidth;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040084 void *src_far, *dest_far;
85 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050086 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040087 src_far = dest_far + nblines * cheight * stride;
88 } else {
89 // Scroll down
90 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050091 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040092 src_far = dest_far - nblines * cheight * stride;
93 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040094 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -050095 if (attr < 0)
96 attr = 0;
Kevin O'Connorb8886952012-02-02 20:56:38 -050097 if (cwidth == 1)
98 attr = (attr&1) | ((attr&1)<<1);
99 attr &= 3;
100 attr |= (attr<<2) | (attr<<4) | (attr<<6);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500101 int cols = lr.x - ul.x + 1;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400102 int rows = lr.y - ul.y + 1;
103 if (nblines < rows) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500104 memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500105 , stride, (rows - nblines) * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500106 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500107 , stride, (rows - nblines) * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400108 }
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500109 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500110 , stride, nblines * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500111 memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500112 , stride, nblines * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400113}
114
115static void
Kevin O'Connorb9373972012-01-01 11:04:42 -0500116scroll_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 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500133 if (attr < 0)
134 attr = 0;
Kevin O'Connorb9373972012-01-01 11:04:42 -0500135 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);
Kevin O'Connorb9373972012-01-01 11:04:42 -0500140 memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth
141 , stride, nblines * cheight);
142}
143
144static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400145scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
146 , struct cursorpos ul, struct cursorpos lr)
147{
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500148 int cheight = 1;
149 int cwidth = 2;
Kevin O'Connor83047be2012-01-07 18:27:19 -0500150 int stride = GET_BDA(video_cols) * cwidth;
151 void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page);
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400152 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500153 dest_far += ul.y * cheight * stride + ul.x * cwidth;
154 src_far = dest_far + nblines * cheight * stride;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400155 } else {
156 // Scroll down
157 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500158 dest_far += lr.y * cheight * stride + ul.x * cwidth;
159 src_far = dest_far - nblines * cheight * stride;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400160 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400161 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500162 if (attr < 0)
163 attr = 0x07;
164 attr = (attr << 8) | ' ';
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500165 int cols = lr.x - ul.x + 1;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400166 int rows = lr.y - ul.y + 1;
167 u16 seg = GET_GLOBAL(vmode_g->sstart);
168 if (nblines < rows)
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500169 dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth
170 , stride, (rows - nblines) * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500171 memset16_stride(seg, dest_far, attr, cols * cwidth
172 , stride, nblines * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400173}
174
175void
176vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
177{
178 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500179 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400180 if (!vmode_g)
181 return;
182
183 // FIXME gfx mode not complete
184 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500185 case MM_TEXT:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400186 scroll_text(vmode_g, nblines, attr, ul, lr);
187 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500188 case MM_PLANAR:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400189 scroll_pl4(vmode_g, nblines, attr, ul, lr);
190 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500191 case MM_CGA:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400192 scroll_cga(vmode_g, nblines, attr, ul, lr);
193 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500194 case MM_DIRECT:
195 case MM_PACKED:
Kevin O'Connorb9373972012-01-01 11:04:42 -0500196 scroll_lin(vmode_g, nblines, attr, ul, lr);
197 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400198 default:
199 break;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400200 }
201}
202
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400203
204/****************************************************************
205 * Read/write characters to screen
206 ****************************************************************/
207
208static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400209write_gfx_char_pl4(struct vgamode_s *vmode_g
210 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400211{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400212 u16 nbcols = GET_BDA(video_cols);
213 if (cp.x >= nbcols)
214 return;
215
Kevin O'Connor87233e92011-12-23 21:40:34 -0500216 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400217 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 }
Kevin O'Connor918b1562009-05-25 11:05:18 -0400228 u16 addr = cp.x + cp.y * cheight * nbcols;
Kevin O'Connor09262412009-05-25 11:44:11 -0400229 u16 src = ca.car * cheight;
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500230 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);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400241 }
242 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500243 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400244}
245
246static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400247write_gfx_char_cga(struct vgamode_s *vmode_g
248 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400249{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400250 u16 nbcols = GET_BDA(video_cols);
251 if (cp.x >= nbcols)
252 return;
253
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400254 u8 *fdata_g = vgafont8;
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500255 u8 bpp = GET_GLOBAL(vmode_g->depth);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400256 u16 addr = (cp.x * bpp) + cp.y * 320;
Kevin O'Connor09262412009-05-25 11:44:11 -0400257 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400258 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;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400263 if (bpp == 1) {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500264 u8 colors = (ca.attr & 0x01) ? 0xff : 0x00;
265 u8 pixels = colors & GET_GLOBAL(fdata_g[src + i]);
Kevin O'Connor09262412009-05-25 11:44:11 -0400266 if (ca.attr & 0x80)
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500267 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
268 SET_FARVAR(SEG_CTEXT, *dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400269 } else {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500270 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);
Kevin O'Connorb3064592012-08-14 21:20:10 -0400276 pixels = cpu_to_be16(pixels);
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500277 if (ca.attr & 0x80)
278 pixels ^= GET_FARVAR(SEG_GRAPH, *(u16*)dest_far);
279 SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400280 }
281 }
282}
283
284static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400285write_gfx_char_lin(struct vgamode_s *vmode_g
286 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400287{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400288 // Get the dimensions
289 u16 nbcols = GET_BDA(video_cols);
290 if (cp.x >= nbcols)
291 return;
292
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400293 u8 *fdata_g = vgafont8;
Kevin O'Connor918b1562009-05-25 11:05:18 -0400294 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
Kevin O'Connor09262412009-05-25 11:44:11 -0400295 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400296 u8 i;
297 for (i = 0; i < 8; i++) {
298 u8 *dest_far = (void*)(addr + i * nbcols * 8);
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500299 u8 fontline = GET_GLOBAL(fdata_g[src + i]);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400300 u8 j;
301 for (j = 0; j < 8; j++) {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500302 u8 pixel = (fontline & (0x80>>j)) ? ca.attr : 0x00;
303 SET_FARVAR(SEG_GRAPH, dest_far[j], pixel);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400304 }
305 }
306}
307
Kevin O'Connord3b38152009-05-26 00:05:37 -0400308static void
309write_text_char(struct vgamode_s *vmode_g
310 , struct cursorpos cp, struct carattr ca)
311{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400312 // Compute the address
Kevin O'Connor83047be2012-01-07 18:27:19 -0500313 u16 nbcols = GET_BDA(video_cols);
314 void *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
Kevin O'Connord3b38152009-05-26 00:05:37 -0400315 + (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
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400325void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400326vgafb_write_char(struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400327{
328 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500329 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400330 if (!vmode_g)
331 return;
332
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400333 // FIXME gfx mode not complete
Kevin O'Connord3b38152009-05-26 00:05:37 -0400334 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500335 case MM_TEXT:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400336 write_text_char(vmode_g, cp, ca);
337 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500338 case MM_PLANAR:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400339 write_gfx_char_pl4(vmode_g, cp, ca);
340 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500341 case MM_CGA:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400342 write_gfx_char_cga(vmode_g, cp, ca);
343 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500344 case MM_DIRECT:
345 case MM_PACKED:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400346 write_gfx_char_lin(vmode_g, cp, ca);
347 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400348 default:
349 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400350 }
351}
352
Kevin O'Connor09262412009-05-25 11:44:11 -0400353struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400354vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400355{
356 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500357 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400358 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400359 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400360
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500361 if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
Kevin O'Connord3b38152009-05-26 00:05:37 -0400362 // FIXME gfx mode
363 dprintf(1, "Read char in graphics mode\n");
364 goto fail;
365 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400366
Kevin O'Connord3b38152009-05-26 00:05:37 -0400367 // Compute the address
Kevin O'Connor83047be2012-01-07 18:27:19 -0500368 u16 nbcols = GET_BDA(video_cols);
369 u16 *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
Kevin O'Connord3b38152009-05-26 00:05:37 -0400370 + (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};
Kevin O'Connor09262412009-05-25 11:44:11 -0400373 return ca;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400374
375fail: ;
376 struct carattr ca2 = {0, 0, 0};
377 return ca2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400378}
379
380
381/****************************************************************
382 * Read/write pixels
383 ****************************************************************/
384
385void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400386vgafb_write_pixel(u8 color, u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400387{
388 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500389 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400390 if (!vmode_g)
391 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400392
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500393 u8 *addr_far, mask, attr, data, i;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400394 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500395 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400396 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
397 mask = 0x80 >> (x & 0x07);
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500398 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);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400407 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500408 case MM_CGA:
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500409 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400410 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400411 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400412 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
413 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400414 addr_far += 0x2000;
415 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500416 if (GET_GLOBAL(vmode_g->depth) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400417 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
418 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400419 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400420 attr = (color & 0x01) << (7 - (x & 0x07));
421 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400422 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400423 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400424 data ^= attr;
425 } else {
426 data &= ~mask;
427 data |= attr;
428 }
429 SET_FARVAR(SEG_CTEXT, *addr_far, data);
430 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500431 case MM_DIRECT:
432 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400433 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
434 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400435 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400436 default:
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500437 case MM_TEXT:
438 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400439 }
440}
441
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400442u8
443vgafb_read_pixel(u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400444{
445 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500446 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400447 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400448 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400449
450 u8 *addr_far, mask, attr=0, data, i;
451 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500452 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400453 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
454 mask = 0x80 >> (x & 0x07);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400455 attr = 0x00;
456 for (i = 0; i < 4; i++) {
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500457 stdvga_planar4_plane(i);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400458 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
459 if (data > 0)
460 attr |= (0x01 << i);
461 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500462 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400463 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500464 case MM_CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400465 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
466 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400467 addr_far += 0x2000;
468 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500469 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400470 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400471 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400472 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400473 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500474 case MM_DIRECT:
475 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400476 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400477 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
478 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400479 default:
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500480 case MM_TEXT:
481 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400482 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400483 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400484}