blob: 1fa11b55da6400b5697893fd2c1434c9eac22fb8 [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
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040010#include "util.h" // dprintf
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'Connorfa9c66a2013-09-14 19:10:40 -040013#include "string.h" // memset_far
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040014
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040015
16/****************************************************************
17 * Screen scrolling
18 ****************************************************************/
19
Kevin O'Connor2c34f412009-05-31 15:25:14 -040020static inline void *
21memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040022{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040023 for (; lines; lines--, dst+=stride, src+=stride)
24 memcpy_far(seg, dst, seg, src, copylen);
25 return dst;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040026}
27
Kevin O'Connor2c34f412009-05-31 15:25:14 -040028static inline void
29memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040030{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040031 for (; lines; lines--, dst+=stride)
32 memset_far(seg, dst, val, setlen);
33}
34
35static inline void
36memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
37{
38 for (; lines; lines--, dst+=stride)
39 memset16_far(seg, dst, val, setlen);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040040}
41
42static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040043scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
44 , struct cursorpos ul, struct cursorpos lr)
45{
Kevin O'Connor68ab0412012-01-01 10:54:19 -050046 int cheight = GET_GLOBAL(vmode_g->cheight);
47 int cwidth = 1;
48 int stride = GET_BDA(video_cols) * cwidth;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040049 void *src_far, *dest_far;
50 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050051 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040052 src_far = dest_far + nblines * cheight * stride;
53 } else {
54 // Scroll down
55 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050056 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040057 src_far = dest_far - nblines * cheight * stride;
58 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040059 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040060 if (attr < 0)
61 attr = 0;
Kevin O'Connor160d34a2012-01-16 18:48:26 -050062 int cols = lr.x - ul.x + 1;
63 int rows = lr.y - ul.y + 1;
64 int i;
65 for (i=0; i<4; i++) {
66 stdvga_planar4_plane(i);
67 void *dest = dest_far;
68 if (nblines < rows)
69 dest = memcpy_stride(SEG_GRAPH, dest, src_far, cols * cwidth
70 , stride, (rows - nblines) * cheight);
71 u8 pixels = (attr & (1<<i)) ? 0xff : 0x00;
72 memset_stride(SEG_GRAPH, dest, pixels, cols * cwidth
73 , stride, nblines * cheight);
74 }
75 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040076}
77
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040078static void
79scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
80 , struct cursorpos ul, struct cursorpos lr)
81{
Kevin O'Connor68ab0412012-01-01 10:54:19 -050082 int cheight = GET_GLOBAL(vmode_g->cheight) / 2;
Kevin O'Connor80da87d2012-01-02 11:13:14 -050083 int cwidth = GET_GLOBAL(vmode_g->depth);
Kevin O'Connor68ab0412012-01-01 10:54:19 -050084 int stride = GET_BDA(video_cols) * cwidth;
Kevin O'Connor2c34f412009-05-31 15:25:14 -040085 void *src_far, *dest_far;
86 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -050087 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040088 src_far = dest_far + nblines * cheight * stride;
89 } else {
90 // Scroll down
91 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -050092 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040093 src_far = dest_far - nblines * cheight * stride;
94 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040095 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -050096 if (attr < 0)
97 attr = 0;
Kevin O'Connorb8886952012-02-02 20:56:38 -050098 if (cwidth == 1)
99 attr = (attr&1) | ((attr&1)<<1);
100 attr &= 3;
101 attr |= (attr<<2) | (attr<<4) | (attr<<6);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500102 int cols = lr.x - ul.x + 1;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400103 int rows = lr.y - ul.y + 1;
104 if (nblines < rows) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500105 memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500106 , stride, (rows - nblines) * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500107 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500108 , stride, (rows - nblines) * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400109 }
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500110 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500111 , stride, nblines * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500112 memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth
Kevin O'Connorae6eb8f2012-01-01 10:33:51 -0500113 , stride, nblines * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400114}
115
116static void
Kevin O'Connorb9373972012-01-01 11:04:42 -0500117scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr
118 , struct cursorpos ul, struct cursorpos lr)
119{
120 int cheight = 8;
121 int cwidth = 8;
122 int stride = GET_BDA(video_cols) * cwidth;
123 void *src_far, *dest_far;
124 if (nblines >= 0) {
125 dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth);
126 src_far = dest_far + nblines * cheight * stride;
127 } else {
128 // Scroll down
129 nblines = -nblines;
130 dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth);
131 src_far = dest_far - nblines * cheight * stride;
132 stride = -stride;
133 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500134 if (attr < 0)
135 attr = 0;
Kevin O'Connorb9373972012-01-01 11:04:42 -0500136 int cols = lr.x - ul.x + 1;
137 int rows = lr.y - ul.y + 1;
138 if (nblines < rows)
139 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols * cwidth
140 , stride, (rows - nblines) * cheight);
Kevin O'Connorb9373972012-01-01 11:04:42 -0500141 memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth
142 , stride, nblines * cheight);
143}
144
145static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400146scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
147 , struct cursorpos ul, struct cursorpos lr)
148{
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500149 int cheight = 1;
150 int cwidth = 2;
Kevin O'Connor83047be2012-01-07 18:27:19 -0500151 int stride = GET_BDA(video_cols) * cwidth;
152 void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page);
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400153 if (nblines >= 0) {
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500154 dest_far += ul.y * cheight * stride + ul.x * cwidth;
155 src_far = dest_far + nblines * cheight * stride;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400156 } else {
157 // Scroll down
158 nblines = -nblines;
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500159 dest_far += lr.y * cheight * stride + ul.x * cwidth;
160 src_far = dest_far - nblines * cheight * stride;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400161 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400162 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500163 if (attr < 0)
164 attr = 0x07;
165 attr = (attr << 8) | ' ';
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500166 int cols = lr.x - ul.x + 1;
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400167 int rows = lr.y - ul.y + 1;
168 u16 seg = GET_GLOBAL(vmode_g->sstart);
169 if (nblines < rows)
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500170 dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth
171 , stride, (rows - nblines) * cheight);
Kevin O'Connor68ab0412012-01-01 10:54:19 -0500172 memset16_stride(seg, dest_far, attr, cols * cwidth
173 , stride, nblines * cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400174}
175
176void
177vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
178{
179 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500180 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400181 if (!vmode_g)
182 return;
183
184 // FIXME gfx mode not complete
185 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500186 case MM_TEXT:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400187 scroll_text(vmode_g, nblines, attr, ul, lr);
188 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500189 case MM_PLANAR:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400190 scroll_pl4(vmode_g, nblines, attr, ul, lr);
191 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500192 case MM_CGA:
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400193 scroll_cga(vmode_g, nblines, attr, ul, lr);
194 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500195 case MM_DIRECT:
196 case MM_PACKED:
Kevin O'Connorb9373972012-01-01 11:04:42 -0500197 scroll_lin(vmode_g, nblines, attr, ul, lr);
198 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400199 default:
200 break;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400201 }
202}
203
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400204
205/****************************************************************
206 * Read/write characters to screen
207 ****************************************************************/
208
209static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400210write_gfx_char_pl4(struct vgamode_s *vmode_g
211 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400212{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400213 u16 nbcols = GET_BDA(video_cols);
214 if (cp.x >= nbcols)
215 return;
216
Kevin O'Connor87233e92011-12-23 21:40:34 -0500217 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400218 u8 *fdata_g;
219 switch (cheight) {
220 case 14:
221 fdata_g = vgafont14;
222 break;
223 case 16:
224 fdata_g = vgafont16;
225 break;
226 default:
227 fdata_g = vgafont8;
228 }
Kevin O'Connor918b1562009-05-25 11:05:18 -0400229 u16 addr = cp.x + cp.y * cheight * nbcols;
Kevin O'Connor09262412009-05-25 11:44:11 -0400230 u16 src = ca.car * cheight;
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500231 int i;
232 for (i=0; i<4; i++) {
233 stdvga_planar4_plane(i);
234 u8 colors = ((ca.attr & (1<<i)) ? 0xff : 0x00);
235 int j;
236 for (j = 0; j < cheight; j++) {
237 u8 *dest_far = (void*)(addr + j * nbcols);
238 u8 pixels = colors & GET_GLOBAL(fdata_g[src + j]);
239 if (ca.attr & 0x80)
240 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
241 SET_FARVAR(SEG_GRAPH, *dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400242 }
243 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500244 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400245}
246
247static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400248write_gfx_char_cga(struct vgamode_s *vmode_g
249 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400250{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400251 u16 nbcols = GET_BDA(video_cols);
252 if (cp.x >= nbcols)
253 return;
254
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400255 u8 *fdata_g = vgafont8;
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500256 u8 bpp = GET_GLOBAL(vmode_g->depth);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400257 u16 addr = (cp.x * bpp) + cp.y * 320;
Kevin O'Connor09262412009-05-25 11:44:11 -0400258 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400259 u8 i;
260 for (i = 0; i < 8; i++) {
261 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
262 if (i & 1)
263 dest_far += 0x2000;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400264 if (bpp == 1) {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500265 u8 colors = (ca.attr & 0x01) ? 0xff : 0x00;
266 u8 pixels = colors & GET_GLOBAL(fdata_g[src + i]);
Kevin O'Connor09262412009-05-25 11:44:11 -0400267 if (ca.attr & 0x80)
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500268 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
269 SET_FARVAR(SEG_CTEXT, *dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400270 } else {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500271 u16 pixels = 0;
272 u8 fontline = GET_GLOBAL(fdata_g[src + i]);
273 int j;
274 for (j = 0; j < 8; j++)
275 if (fontline & (1<<j))
276 pixels |= (ca.attr & 0x03) << (j*2);
Kevin O'Connorb3064592012-08-14 21:20:10 -0400277 pixels = cpu_to_be16(pixels);
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500278 if (ca.attr & 0x80)
279 pixels ^= GET_FARVAR(SEG_GRAPH, *(u16*)dest_far);
280 SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400281 }
282 }
283}
284
285static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400286write_gfx_char_lin(struct vgamode_s *vmode_g
287 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400288{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400289 // Get the dimensions
290 u16 nbcols = GET_BDA(video_cols);
291 if (cp.x >= nbcols)
292 return;
293
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400294 u8 *fdata_g = vgafont8;
Kevin O'Connor918b1562009-05-25 11:05:18 -0400295 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
Kevin O'Connor09262412009-05-25 11:44:11 -0400296 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400297 u8 i;
298 for (i = 0; i < 8; i++) {
299 u8 *dest_far = (void*)(addr + i * nbcols * 8);
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500300 u8 fontline = GET_GLOBAL(fdata_g[src + i]);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400301 u8 j;
302 for (j = 0; j < 8; j++) {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500303 u8 pixel = (fontline & (0x80>>j)) ? ca.attr : 0x00;
304 SET_FARVAR(SEG_GRAPH, dest_far[j], pixel);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400305 }
306 }
307}
308
Kevin O'Connord3b38152009-05-26 00:05:37 -0400309static void
310write_text_char(struct vgamode_s *vmode_g
311 , struct cursorpos cp, struct carattr ca)
312{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400313 // Compute the address
Kevin O'Connor83047be2012-01-07 18:27:19 -0500314 u16 nbcols = GET_BDA(video_cols);
315 void *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
Kevin O'Connord3b38152009-05-26 00:05:37 -0400316 + (cp.x + cp.y * nbcols) * 2);
317
318 if (ca.use_attr) {
319 u16 dummy = (ca.attr << 8) | ca.car;
320 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
321 } else {
322 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
323 }
324}
325
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400326void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400327vgafb_write_char(struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400328{
329 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500330 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400331 if (!vmode_g)
332 return;
333
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400334 // FIXME gfx mode not complete
Kevin O'Connord3b38152009-05-26 00:05:37 -0400335 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500336 case MM_TEXT:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400337 write_text_char(vmode_g, cp, ca);
338 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500339 case MM_PLANAR:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400340 write_gfx_char_pl4(vmode_g, cp, ca);
341 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500342 case MM_CGA:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400343 write_gfx_char_cga(vmode_g, cp, ca);
344 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500345 case MM_DIRECT:
346 case MM_PACKED:
Kevin O'Connord3b38152009-05-26 00:05:37 -0400347 write_gfx_char_lin(vmode_g, cp, ca);
348 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400349 default:
350 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400351 }
352}
353
Kevin O'Connor09262412009-05-25 11:44:11 -0400354struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400355vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400356{
357 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500358 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400359 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400360 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400361
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500362 if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
Kevin O'Connord3b38152009-05-26 00:05:37 -0400363 // FIXME gfx mode
364 dprintf(1, "Read char in graphics mode\n");
365 goto fail;
366 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400367
Kevin O'Connord3b38152009-05-26 00:05:37 -0400368 // Compute the address
Kevin O'Connor83047be2012-01-07 18:27:19 -0500369 u16 nbcols = GET_BDA(video_cols);
370 u16 *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
Kevin O'Connord3b38152009-05-26 00:05:37 -0400371 + (cp.x + cp.y * nbcols) * 2);
372 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
373 struct carattr ca = {v, v>>8, 0};
Kevin O'Connor09262412009-05-25 11:44:11 -0400374 return ca;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400375
376fail: ;
377 struct carattr ca2 = {0, 0, 0};
378 return ca2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400379}
380
381
382/****************************************************************
383 * Read/write pixels
384 ****************************************************************/
385
386void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400387vgafb_write_pixel(u8 color, u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400388{
389 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500390 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400391 if (!vmode_g)
392 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400393
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500394 u8 *addr_far, mask, attr, data, i;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400395 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500396 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400397 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
398 mask = 0x80 >> (x & 0x07);
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500399 for (i=0; i<4; i++) {
400 stdvga_planar4_plane(i);
401 u8 colors = (color & (1<<i)) ? 0xff : 0x00;
402 u8 orig = GET_FARVAR(SEG_GRAPH, *addr_far);
403 if (color & 0x80)
404 colors ^= orig;
405 SET_FARVAR(SEG_GRAPH, *addr_far, (colors & mask) | (orig & ~mask));
406 }
407 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400408 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500409 case MM_CGA:
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500410 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400411 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400412 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400413 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
414 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400415 addr_far += 0x2000;
416 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500417 if (GET_GLOBAL(vmode_g->depth) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400418 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
419 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400420 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400421 attr = (color & 0x01) << (7 - (x & 0x07));
422 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400423 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400424 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400425 data ^= attr;
426 } else {
427 data &= ~mask;
428 data |= attr;
429 }
430 SET_FARVAR(SEG_CTEXT, *addr_far, data);
431 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500432 case MM_DIRECT:
433 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400434 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
435 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400436 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400437 default:
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500438 case MM_TEXT:
439 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400440 }
441}
442
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400443u8
444vgafb_read_pixel(u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400445{
446 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500447 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400448 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400449 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400450
451 u8 *addr_far, mask, attr=0, data, i;
452 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500453 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400454 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
455 mask = 0x80 >> (x & 0x07);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400456 attr = 0x00;
457 for (i = 0; i < 4; i++) {
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500458 stdvga_planar4_plane(i);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400459 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
460 if (data > 0)
461 attr |= (0x01 << i);
462 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500463 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400464 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500465 case MM_CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400466 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
467 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400468 addr_far += 0x2000;
469 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500470 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400471 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400472 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400473 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400474 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500475 case MM_DIRECT:
476 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400477 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400478 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
479 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400480 default:
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500481 case MM_TEXT:
482 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400483 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400484 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400485}