blob: f0bd71ef563dfadfee6db5bf3644eefbb8c31981 [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
8#include "biosvar.h" // GET_BDA
9#include "util.h" // memset_far
Kevin O'Connor160d34a2012-01-16 18:48:26 -050010#include "stdvga.h" // stdvga_planar4_plane
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040011
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040012
13/****************************************************************
14 * Screen scrolling
15 ****************************************************************/
16
Kevin O'Connor2c34f412009-05-31 15:25:14 -040017static inline void *
18memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040019{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040020 for (; lines; lines--, dst+=stride, src+=stride)
21 memcpy_far(seg, dst, seg, src, copylen);
22 return dst;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040023}
24
Kevin O'Connor2c34f412009-05-31 15:25:14 -040025static inline void
26memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040027{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040028 for (; lines; lines--, dst+=stride)
29 memset_far(seg, dst, val, setlen);
30}
31
32static inline void
33memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
34{
35 for (; lines; lines--, dst+=stride)
36 memset16_far(seg, dst, val, setlen);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040037}
38
39static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040040scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
41 , struct cursorpos ul, struct cursorpos lr)
42{
Kevin O'Connor68ab0412012-01-01 10:54:19 -050043 int cheight = GET_GLOBAL(vmode_g->cheight);
44 int cwidth = 1;
45 int stride = GET_BDA(video_cols) * cwidth;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040046 void *src_far, *dest_far;
47 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050048 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040049 src_far = dest_far + nblines * cheight * stride;
50 } else {
51 // Scroll down
52 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050053 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040054 src_far = dest_far - nblines * cheight * stride;
55 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040056 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040057 if (attr < 0)
58 attr = 0;
Kevin O'Connor160d34a2012-01-16 18:48:26 -050059 int cols = lr.x - ul.x + 1;
60 int rows = lr.y - ul.y + 1;
61 int i;
62 for (i=0; i<4; i++) {
63 stdvga_planar4_plane(i);
64 void *dest = dest_far;
65 if (nblines < rows)
66 dest = memcpy_stride(SEG_GRAPH, dest, src_far, cols * cwidth
67 , stride, (rows - nblines) * cheight);
68 u8 pixels = (attr & (1<<i)) ? 0xff : 0x00;
69 memset_stride(SEG_GRAPH, dest, pixels, cols * cwidth
70 , stride, nblines * cheight);
71 }
72 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040073}
74
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040075static void
76scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
77 , struct cursorpos ul, struct cursorpos lr)
78{
Kevin O'Connor68ab0412012-01-01 10:54:19 -050079 int cheight = GET_GLOBAL(vmode_g->cheight) / 2;
Kevin O'Connor80da87d2012-01-02 11:13:14 -050080 int cwidth = GET_GLOBAL(vmode_g->depth);
Kevin O'Connor68ab0412012-01-01 10:54:19 -050081 int stride = GET_BDA(video_cols) * cwidth;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040082 void *src_far, *dest_far;
83 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050084 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040085 src_far = dest_far + nblines * cheight * stride;
86 } else {
87 // Scroll down
88 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050089 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040090 src_far = dest_far - nblines * cheight * stride;
91 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040092 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -050093 if (attr < 0)
94 attr = 0;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050095 int cols = lr.x - ul.x + 1;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040096 int rows = lr.y - ul.y + 1;
97 if (nblines < rows) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050098 memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -050099 , stride, (rows - nblines) * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500100 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500101 , stride, (rows - nblines) * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400102 }
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500103 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500104 , stride, nblines * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500105 memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500106 , stride, nblines * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400107}
108
109static void
Kevin O'Connorb9373972012-01-01 11:04:42 -0500110scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr
111 , struct cursorpos ul, struct cursorpos lr)
112{
113 int cheight = 8;
114 int cwidth = 8;
115 int stride = GET_BDA(video_cols) * cwidth;
116 void *src_far, *dest_far;
117 if (nblines >= 0) {
118 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
119 src_far = dest_far + nblines * cheight * stride;
120 } else {
121 // Scroll down
122 nblines = -nblines;
123 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
124 src_far = dest_far - nblines * cheight * stride;
125 stride = -stride;
126 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500127 if (attr < 0)
128 attr = 0;
Kevin O'Connorb9373972012-01-01 11:04:42 -0500129 int cols = lr.x - ul.x + 1;
130 int rows = lr.y - ul.y + 1;
131 if (nblines < rows)
132 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols * cwidth
133 , stride, (rows - nblines) * cheight);
Kevin O'Connorb9373972012-01-01 11:04:42 -0500134 memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth
135 , stride, nblines * cheight);
136}
137
138static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400139scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
140 , struct cursorpos ul, struct cursorpos lr)
141{
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500142 int cheight = 1;
143 int cwidth = 2;
Kevin O'Connor83047be2012-01-07 18:27:19 -0500144 int stride = GET_BDA(video_cols) * cwidth;
145 void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page);
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400146 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500147 dest_far += ul.y * cheight * stride + ul.x * cwidth;
148 src_far = dest_far + nblines * cheight * stride;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400149 } else {
150 // Scroll down
151 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500152 dest_far += lr.y * cheight * stride + ul.x * cwidth;
153 src_far = dest_far - nblines * cheight * stride;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400154 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400155 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500156 if (attr < 0)
157 attr = 0x07;
158 attr = (attr << 8) | ' ';
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500159 int cols = lr.x - ul.x + 1;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400160 int rows = lr.y - ul.y + 1;
161 u16 seg = GET_GLOBAL(vmode_g->sstart);
162 if (nblines < rows)
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500163 dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth
164 , stride, (rows - nblines) * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500165 memset16_stride(seg, dest_far, attr, cols * cwidth
166 , stride, nblines * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400167}
168
169void
170vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
171{
172 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500173 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400174 if (!vmode_g)
175 return;
176
177 // FIXME gfx mode not complete
178 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500179 case MM_TEXT:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400180 scroll_text(vmode_g, nblines, attr, ul, lr);
181 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500182 case MM_PLANAR:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400183 scroll_pl4(vmode_g, nblines, attr, ul, lr);
184 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500185 case MM_CGA:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400186 scroll_cga(vmode_g, nblines, attr, ul, lr);
187 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500188 case MM_DIRECT:
189 case MM_PACKED:
Kevin O'Connorb9373972012-01-01 11:04:42 -0500190 scroll_lin(vmode_g, nblines, attr, ul, lr);
191 break;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400192 }
193}
194
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400195
196/****************************************************************
197 * Read/write characters to screen
198 ****************************************************************/
199
200static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400201write_gfx_char_pl4(struct vgamode_s *vmode_g
202 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400203{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400204 u16 nbcols = GET_BDA(video_cols);
205 if (cp.x >= nbcols)
206 return;
207
Kevin O'Connor87233e92011-12-23 21:40:34 -0500208 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400209 u8 *fdata_g;
210 switch (cheight) {
211 case 14:
212 fdata_g = vgafont14;
213 break;
214 case 16:
215 fdata_g = vgafont16;
216 break;
217 default:
218 fdata_g = vgafont8;
219 }
Kevin O'Connor918b1562009-05-25 11:05:18 -0400220 u16 addr = cp.x + cp.y * cheight * nbcols;
Kevin O'Connor09262412009-05-25 11:44:11 -0400221 u16 src = ca.car * cheight;
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500222 int i;
223 for (i=0; i<4; i++) {
224 stdvga_planar4_plane(i);
225 u8 colors = ((ca.attr & (1<<i)) ? 0xff : 0x00);
226 int j;
227 for (j = 0; j < cheight; j++) {
228 u8 *dest_far = (void*)(addr + j * nbcols);
229 u8 pixels = colors & GET_GLOBAL(fdata_g[src + j]);
230 if (ca.attr & 0x80)
231 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
232 SET_FARVAR(SEG_GRAPH, *dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400233 }
234 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500235 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400236}
237
238static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400239write_gfx_char_cga(struct vgamode_s *vmode_g
240 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400241{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400242 u16 nbcols = GET_BDA(video_cols);
243 if (cp.x >= nbcols)
244 return;
245
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400246 u8 *fdata_g = vgafont8;
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500247 u8 bpp = GET_GLOBAL(vmode_g->depth);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400248 u16 addr = (cp.x * bpp) + cp.y * 320;
Kevin O'Connor09262412009-05-25 11:44:11 -0400249 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400250 u8 i;
251 for (i = 0; i < 8; i++) {
252 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
253 if (i & 1)
254 dest_far += 0x2000;
255 u8 mask = 0x80;
256 if (bpp == 1) {
257 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400258 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400259 data = GET_FARVAR(SEG_CTEXT, *dest_far);
260 u8 j;
261 for (j = 0; j < 8; j++) {
262 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400263 if (ca.attr & 0x80)
264 data ^= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400265 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400266 data |= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400267 }
268 mask >>= 1;
269 }
270 SET_FARVAR(SEG_CTEXT, *dest_far, data);
271 } else {
272 while (mask > 0) {
273 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400274 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400275 data = GET_FARVAR(SEG_CTEXT, *dest_far);
276 u8 j;
277 for (j = 0; j < 4; j++) {
278 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400279 if (ca.attr & 0x80)
280 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400281 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400282 data |= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400283 }
284 mask >>= 1;
285 }
286 SET_FARVAR(SEG_CTEXT, *dest_far, data);
287 dest_far += 1;
288 }
289 }
290 }
291}
292
293static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400294write_gfx_char_lin(struct vgamode_s *vmode_g
295 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400296{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400297 // Get the dimensions
298 u16 nbcols = GET_BDA(video_cols);
299 if (cp.x >= nbcols)
300 return;
301
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400302 u8 *fdata_g = vgafont8;
Kevin O'Connor918b1562009-05-25 11:05:18 -0400303 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
Kevin O'Connor09262412009-05-25 11:44:11 -0400304 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400305 u8 i;
306 for (i = 0; i < 8; i++) {
307 u8 *dest_far = (void*)(addr + i * nbcols * 8);
308 u8 mask = 0x80;
309 u8 j;
310 for (j = 0; j < 8; j++) {
311 u8 data = 0x00;
312 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400313 data = ca.attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400314 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
315 mask >>= 1;
316 }
317 }
318}
319
Kevin O'Connord3b38152009-05-26 00:05:37 -0400320static void
321write_text_char(struct vgamode_s *vmode_g
322 , struct cursorpos cp, struct carattr ca)
323{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400324 // Compute the address
Kevin O'Connor83047be2012-01-07 18:27:19 -0500325 u16 nbcols = GET_BDA(video_cols);
326 void *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
Kevin O'Connord3b38152009-05-26 00:05:37 -0400327 + (cp.x + cp.y * nbcols) * 2);
328
329 if (ca.use_attr) {
330 u16 dummy = (ca.attr << 8) | ca.car;
331 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
332 } else {
333 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
334 }
335}
336
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400337void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400338vgafb_write_char(struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400339{
340 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500341 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400342 if (!vmode_g)
343 return;
344
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400345 // FIXME gfx mode not complete
Kevin O'Connord3b38152009-05-26 00:05:37 -0400346 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500347 case MM_TEXT:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400348 write_text_char(vmode_g, cp, ca);
349 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500350 case MM_PLANAR:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400351 write_gfx_char_pl4(vmode_g, cp, ca);
352 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500353 case MM_CGA:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400354 write_gfx_char_cga(vmode_g, cp, ca);
355 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500356 case MM_DIRECT:
357 case MM_PACKED:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400358 write_gfx_char_lin(vmode_g, cp, ca);
359 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400360 }
361}
362
Kevin O'Connor09262412009-05-25 11:44:11 -0400363struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400364vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400365{
366 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500367 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400368 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400369 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400370
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500371 if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
Kevin O'Connord3b38152009-05-26 00:05:37 -0400372 // FIXME gfx mode
373 dprintf(1, "Read char in graphics mode\n");
374 goto fail;
375 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400376
Kevin O'Connord3b38152009-05-26 00:05:37 -0400377 // Compute the address
Kevin O'Connor83047be2012-01-07 18:27:19 -0500378 u16 nbcols = GET_BDA(video_cols);
379 u16 *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
Kevin O'Connord3b38152009-05-26 00:05:37 -0400380 + (cp.x + cp.y * nbcols) * 2);
381 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
382 struct carattr ca = {v, v>>8, 0};
Kevin O'Connor09262412009-05-25 11:44:11 -0400383 return ca;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400384
385fail: ;
386 struct carattr ca2 = {0, 0, 0};
387 return ca2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400388}
389
390
391/****************************************************************
392 * Read/write pixels
393 ****************************************************************/
394
395void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400396vgafb_write_pixel(u8 color, u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400397{
398 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500399 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400400 if (!vmode_g)
401 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400402
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500403 u8 *addr_far, mask, attr, data, i;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400404 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500405 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400406 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
407 mask = 0x80 >> (x & 0x07);
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500408 for (i=0; i<4; i++) {
409 stdvga_planar4_plane(i);
410 u8 colors = (color & (1<<i)) ? 0xff : 0x00;
411 u8 orig = GET_FARVAR(SEG_GRAPH, *addr_far);
412 if (color & 0x80)
413 colors ^= orig;
414 SET_FARVAR(SEG_GRAPH, *addr_far, (colors & mask) | (orig & ~mask));
415 }
416 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400417 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500418 case MM_CGA:
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500419 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400420 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400421 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400422 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
423 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400424 addr_far += 0x2000;
425 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500426 if (GET_GLOBAL(vmode_g->depth) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400427 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
428 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400429 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400430 attr = (color & 0x01) << (7 - (x & 0x07));
431 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400432 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400433 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400434 data ^= attr;
435 } else {
436 data &= ~mask;
437 data |= attr;
438 }
439 SET_FARVAR(SEG_CTEXT, *addr_far, data);
440 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500441 case MM_DIRECT:
442 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400443 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
444 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400445 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500446 case MM_TEXT:
447 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400448 }
449}
450
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400451u8
452vgafb_read_pixel(u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400453{
454 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500455 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400456 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400457 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400458
459 u8 *addr_far, mask, attr=0, data, i;
460 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500461 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400462 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
463 mask = 0x80 >> (x & 0x07);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400464 attr = 0x00;
465 for (i = 0; i < 4; i++) {
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500466 stdvga_planar4_plane(i);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400467 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
468 if (data > 0)
469 attr |= (0x01 << i);
470 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500471 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400472 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500473 case MM_CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400474 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
475 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400476 addr_far += 0x2000;
477 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500478 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400479 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400480 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400481 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400482 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500483 case MM_DIRECT:
484 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400485 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400486 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
487 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500488 case MM_TEXT:
489 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400490 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400491 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400492}