blob: 2efaab552036d30bda31b7e9b8e26d72e145e848 [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
Kevin O'Connorb3064592012-08-14 21:20:10 -04009#include "byteorder.h" // cpu_to_be16
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040010#include "output.h" // dprintf
Kevin O'Connor160d34a2012-01-16 18:48:26 -050011#include "stdvga.h" // stdvga_planar4_plane
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040012#include "string.h" // memset_far
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040013#include "vgabios.h" // vgafb_scroll
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'Connor1f31f002013-11-30 10:52:45 -050046 int cheight = GET_BDA(char_height);
Kevin O'Connor68ab0412012-01-01 10:54:19 -050047 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'Connor1f31f002013-11-30 10:52:45 -050082 int cheight = GET_BDA(char_height) / 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{
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500120 int cheight = GET_BDA(char_height);
Kevin O'Connorb9373972012-01-01 11:04:42 -0500121 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
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500209static struct segoff_s
210get_font_data(u8 c)
211{
212 int char_height = GET_BDA(char_height);
213 struct segoff_s font;
214 if (char_height == 8 && c >= 128) {
215 font = GET_IVT(0x1f);
216 c -= 128;
217 } else {
218 font = GET_IVT(0x43);
219 }
220 font.offset += c * char_height;
221 return font;
222}
223
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400224static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400225write_gfx_char_pl4(struct vgamode_s *vmode_g
226 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400227{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400228 u16 nbcols = GET_BDA(video_cols);
229 if (cp.x >= nbcols)
230 return;
231
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500232 struct segoff_s font = get_font_data(ca.car);
233 int cheight = GET_BDA(char_height);
234 int cwidth = 1;
235 int stride = nbcols * cwidth;
236 int addr = cp.y * cheight * stride + cp.x * cwidth;
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500237 int i;
238 for (i=0; i<4; i++) {
239 stdvga_planar4_plane(i);
240 u8 colors = ((ca.attr & (1<<i)) ? 0xff : 0x00);
241 int j;
242 for (j = 0; j < cheight; j++) {
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500243 u8 *dest_far = (void*)(addr + j * stride);
244 u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+j));
245 u8 pixels = colors & fontline;
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500246 if (ca.attr & 0x80)
247 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
248 SET_FARVAR(SEG_GRAPH, *dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400249 }
250 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500251 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400252}
253
254static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400255write_gfx_char_cga(struct vgamode_s *vmode_g
256 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400257{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400258 u16 nbcols = GET_BDA(video_cols);
259 if (cp.x >= nbcols)
260 return;
261
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500262 struct segoff_s font = get_font_data(ca.car);
263 int cheight = GET_BDA(char_height) / 2;
264 int cwidth = GET_GLOBAL(vmode_g->depth);
265 int stride = nbcols * cwidth;
266 int addr = cp.y * cheight * stride + cp.x * cwidth;
267 int i;
268 for (i = 0; i < cheight*2; i++) {
269 u8 *dest_far = (void*)(addr + (i >> 1) * stride);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400270 if (i & 1)
271 dest_far += 0x2000;
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500272 u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+i));
273 if (cwidth == 1) {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500274 u8 colors = (ca.attr & 0x01) ? 0xff : 0x00;
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500275 u8 pixels = colors & fontline;
Kevin O'Connor09262412009-05-25 11:44:11 -0400276 if (ca.attr & 0x80)
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500277 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
278 SET_FARVAR(SEG_CTEXT, *dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400279 } else {
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500280 u16 fontline16 = ((fontline & 0xf0) << 4) | (fontline & 0x0f);
281 fontline16 = ((fontline16 & 0x0c0c) << 2) | (fontline16 & 0x0303);
282 fontline16 = ((fontline16 & 0x2222) << 1) | (fontline16 & 0x1111);
283 fontline16 |= fontline16<<1;
284 u16 colors = (((ca.attr & 0x01) ? 0x5555 : 0x0000)
285 | ((ca.attr & 0x02) ? 0xaaaa : 0x0000));
286 u16 pixels = cpu_to_be16(colors & fontline16);
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500287 if (ca.attr & 0x80)
288 pixels ^= GET_FARVAR(SEG_GRAPH, *(u16*)dest_far);
289 SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, pixels);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400290 }
291 }
292}
293
294static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400295write_gfx_char_lin(struct vgamode_s *vmode_g
296 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400297{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400298 // Get the dimensions
299 u16 nbcols = GET_BDA(video_cols);
300 if (cp.x >= nbcols)
301 return;
302
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500303 struct segoff_s font = get_font_data(ca.car);
304 int cheight = GET_BDA(char_height);
305 int cwidth = 8;
306 int stride = nbcols * cwidth;
307 int addr = cp.y * cheight * stride + cp.x * cwidth;
308 int i;
309 for (i = 0; i < cheight; i++) {
310 u8 *dest_far = (void*)(addr + i * stride);
311 u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+i));
312 int j;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400313 for (j = 0; j < 8; j++) {
Kevin O'Connor9a4d0c12012-02-02 20:56:10 -0500314 u8 pixel = (fontline & (0x80>>j)) ? ca.attr : 0x00;
315 SET_FARVAR(SEG_GRAPH, dest_far[j], pixel);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400316 }
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'Connor1f31f002013-11-30 10:52:45 -0500324 int cheight = 1;
325 int cwidth = 2;
326 int stride = GET_BDA(video_cols) * cwidth;
327 int addr = cp.y * cheight * stride + cp.x * cwidth;
328 void *dest_far = (void*)(GET_BDA(video_pagesize) * cp.page + addr);
Kevin O'Connord3b38152009-05-26 00:05:37 -0400329 if (ca.use_attr) {
330 u16 dummy = (ca.attr << 8) | ca.car;
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500331 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)dest_far, dummy);
Kevin O'Connord3b38152009-05-26 00:05:37 -0400332 } else {
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500333 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, ca.car);
Kevin O'Connord3b38152009-05-26 00:05:37 -0400334 }
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'Connora0263082012-04-14 20:22:18 -0400360 default:
361 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400362 }
363}
364
Kevin O'Connor09262412009-05-25 11:44:11 -0400365struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400366vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400367{
368 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500369 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400370 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400371 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400372
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500373 if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
Kevin O'Connord3b38152009-05-26 00:05:37 -0400374 // FIXME gfx mode
375 dprintf(1, "Read char in graphics mode\n");
376 goto fail;
377 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400378
Kevin O'Connord3b38152009-05-26 00:05:37 -0400379 // Compute the address
Kevin O'Connor1f31f002013-11-30 10:52:45 -0500380 int cheight = 1;
381 int cwidth = 2;
382 int stride = GET_BDA(video_cols) * cwidth;
383 int addr = cp.y * cheight * stride + cp.x * cwidth;
384 u16 *src_far = (void*)(GET_BDA(video_pagesize) * cp.page + addr);
385 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *src_far);
Kevin O'Connord3b38152009-05-26 00:05:37 -0400386 struct carattr ca = {v, v>>8, 0};
Kevin O'Connor09262412009-05-25 11:44:11 -0400387 return ca;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400388
389fail: ;
390 struct carattr ca2 = {0, 0, 0};
391 return ca2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400392}
393
394
395/****************************************************************
396 * Read/write pixels
397 ****************************************************************/
398
399void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400400vgafb_write_pixel(u8 color, u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400401{
402 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500403 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400404 if (!vmode_g)
405 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400406
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500407 u8 *addr_far, mask, attr, data, i;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400408 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500409 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400410 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
411 mask = 0x80 >> (x & 0x07);
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500412 for (i=0; i<4; i++) {
413 stdvga_planar4_plane(i);
414 u8 colors = (color & (1<<i)) ? 0xff : 0x00;
415 u8 orig = GET_FARVAR(SEG_GRAPH, *addr_far);
416 if (color & 0x80)
417 colors ^= orig;
418 SET_FARVAR(SEG_GRAPH, *addr_far, (colors & mask) | (orig & ~mask));
419 }
420 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400421 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500422 case MM_CGA:
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500423 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400424 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400425 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400426 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
427 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400428 addr_far += 0x2000;
429 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500430 if (GET_GLOBAL(vmode_g->depth) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400431 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
432 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400433 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400434 attr = (color & 0x01) << (7 - (x & 0x07));
435 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400436 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400437 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400438 data ^= attr;
439 } else {
440 data &= ~mask;
441 data |= attr;
442 }
443 SET_FARVAR(SEG_CTEXT, *addr_far, data);
444 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500445 case MM_DIRECT:
446 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400447 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
448 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400449 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400450 default:
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500451 case MM_TEXT:
452 return;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400453 }
454}
455
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400456u8
457vgafb_read_pixel(u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400458{
459 // Get the mode
Kevin O'Connor4a73f932012-01-21 11:08:35 -0500460 struct vgamode_s *vmode_g = get_current_mode();
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400461 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400462 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400463
464 u8 *addr_far, mask, attr=0, data, i;
465 switch (GET_GLOBAL(vmode_g->memmodel)) {
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500466 case MM_PLANAR:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400467 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
468 mask = 0x80 >> (x & 0x07);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400469 attr = 0x00;
470 for (i = 0; i < 4; i++) {
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500471 stdvga_planar4_plane(i);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400472 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
473 if (data > 0)
474 attr |= (0x01 << i);
475 }
Kevin O'Connor160d34a2012-01-16 18:48:26 -0500476 stdvga_planar4_plane(-1);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400477 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500478 case MM_CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400479 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
480 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400481 addr_far += 0x2000;
482 data = GET_FARVAR(SEG_CTEXT, *addr_far);
Kevin O'Connor80da87d2012-01-02 11:13:14 -0500483 if (GET_GLOBAL(vmode_g->depth) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400484 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400485 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400486 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400487 break;
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500488 case MM_DIRECT:
489 case MM_PACKED:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400490 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400491 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
492 break;
Kevin O'Connora0263082012-04-14 20:22:18 -0400493 default:
Kevin O'Connord4398ad2012-01-01 12:32:53 -0500494 case MM_TEXT:
495 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400496 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400497 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400498}