blob: 1e1943dc2b6cb126b885a29c33d0f2ff1dbd5969 [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
10#include "vgatables.h" // find_vga_entry
11
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'Connor87233e92011-12-23 21:40:34 -050043 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040044 int stride = GET_BDA(video_cols);
45 void *src_far, *dest_far;
46 if (nblines >= 0) {
47 dest_far = (void*)(ul.y * cheight * stride + ul.x);
48 src_far = dest_far + nblines * cheight * stride;
49 } else {
50 // Scroll down
51 nblines = -nblines;
52 dest_far = (void*)(lr.y * cheight * stride + ul.x);
53 src_far = dest_far - nblines * cheight * stride;
54 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040055 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040056 int cols = lr.x - ul.x + 1;
57 int rows = lr.y - ul.y + 1;
58 if (nblines < rows) {
Kevin O'Connor414d0732009-05-31 22:42:04 -040059 vgahw_grdc_write(0x05, 0x01);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040060 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
61 , (rows - nblines) * cheight);
62 }
63 if (attr < 0)
64 attr = 0;
Kevin O'Connor414d0732009-05-31 22:42:04 -040065 vgahw_grdc_write(0x05, 0x02);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040066 memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
Kevin O'Connor414d0732009-05-31 22:42:04 -040067 vgahw_grdc_write(0x05, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040068}
69
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040070static void
71scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
72 , struct cursorpos ul, struct cursorpos lr)
73{
Kevin O'Connor87233e92011-12-23 21:40:34 -050074 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040075 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040076 int stride = GET_BDA(video_cols) * bpp;
77 void *src_far, *dest_far;
78 if (nblines >= 0) {
79 dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
80 src_far = dest_far + nblines * cheight * stride;
81 } else {
82 // Scroll down
83 nblines = -nblines;
84 dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
85 src_far = dest_far - nblines * cheight * stride;
86 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040087 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040088 int cols = (lr.x - ul.x + 1) * bpp;
89 int rows = lr.y - ul.y + 1;
90 if (nblines < rows) {
91 memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
92 , stride, (rows - nblines) * cheight / 2);
93 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
94 , stride, (rows - nblines) * cheight / 2);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040095 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040096 if (attr < 0)
97 attr = 0;
98 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
99 , stride, nblines * cheight / 2);
100 memset_stride(SEG_CTEXT, dest_far, attr, cols
101 , stride, nblines * cheight / 2);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400102}
103
104static void
105scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
106 , struct cursorpos ul, struct cursorpos lr)
107{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400108 u16 nbrows = GET_BDA(video_rows) + 1;
109 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400110 void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
111 int stride = nbcols * 2;
112 if (nblines >= 0) {
113 dest_far += ul.y * stride + ul.x * 2;
114 src_far = dest_far + nblines * stride;
115 } else {
116 // Scroll down
117 nblines = -nblines;
118 dest_far += lr.y * stride + ul.x * 2;
119 src_far = dest_far - nblines * stride;
120 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400121 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400122 int cols = (lr.x - ul.x + 1) * 2;
123 int rows = lr.y - ul.y + 1;
124 u16 seg = GET_GLOBAL(vmode_g->sstart);
125 if (nblines < rows)
126 dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
127 , (rows - nblines));
128 if (attr < 0)
129 attr = 0x07;
130 attr = (attr << 8) | ' ';
131 memset16_stride(seg, dest_far, attr, cols, stride, nblines);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400132}
133
134void
135vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
136{
137 // Get the mode
138 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
139 if (!vmode_g)
140 return;
141
142 // FIXME gfx mode not complete
143 switch (GET_GLOBAL(vmode_g->memmodel)) {
144 case CTEXT:
145 case MTEXT:
146 scroll_text(vmode_g, nblines, attr, ul, lr);
147 break;
148 case PLANAR4:
149 case PLANAR1:
150 scroll_pl4(vmode_g, nblines, attr, ul, lr);
151 break;
152 case CGA:
153 scroll_cga(vmode_g, nblines, attr, ul, lr);
154 break;
155 default:
156 dprintf(1, "Scroll in graphics mode\n");
157 }
158}
159
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400160void
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400161clear_screen(struct vgamode_s *vmode_g)
162{
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400163 switch (GET_GLOBAL(vmode_g->memmodel)) {
164 case CTEXT:
165 case MTEXT:
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400166 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400167 break;
168 case CGA:
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400169 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400170 break;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400171 default:
172 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
173 // but it should always be 0xf anyway.
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400174 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
Kevin O'Connorae6e1c82009-05-31 01:09:30 -0400175 }
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400176}
177
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400178
179/****************************************************************
180 * Read/write characters to screen
181 ****************************************************************/
182
183static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400184write_gfx_char_pl4(struct vgamode_s *vmode_g
185 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400186{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400187 u16 nbcols = GET_BDA(video_cols);
188 if (cp.x >= nbcols)
189 return;
190
Kevin O'Connor87233e92011-12-23 21:40:34 -0500191 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400192 u8 *fdata_g;
193 switch (cheight) {
194 case 14:
195 fdata_g = vgafont14;
196 break;
197 case 16:
198 fdata_g = vgafont16;
199 break;
200 default:
201 fdata_g = vgafont8;
202 }
Kevin O'Connor918b1562009-05-25 11:05:18 -0400203 u16 addr = cp.x + cp.y * cheight * nbcols;
Kevin O'Connor09262412009-05-25 11:44:11 -0400204 u16 src = ca.car * cheight;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400205 vgahw_sequ_write(0x02, 0x0f);
206 vgahw_grdc_write(0x05, 0x02);
Kevin O'Connor09262412009-05-25 11:44:11 -0400207 if (ca.attr & 0x80)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400208 vgahw_grdc_write(0x03, 0x18);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400209 else
Kevin O'Connor414d0732009-05-31 22:42:04 -0400210 vgahw_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400211 u8 i;
212 for (i = 0; i < cheight; i++) {
213 u8 *dest_far = (void*)(addr + i * nbcols);
214 u8 j;
215 for (j = 0; j < 8; j++) {
216 u8 mask = 0x80 >> j;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400217 vgahw_grdc_write(0x08, mask);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400218 GET_FARVAR(SEG_GRAPH, *dest_far);
219 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400220 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400221 else
222 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
223 }
224 }
Kevin O'Connor414d0732009-05-31 22:42:04 -0400225 vgahw_grdc_write(0x08, 0xff);
226 vgahw_grdc_write(0x05, 0x00);
227 vgahw_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400228}
229
230static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400231write_gfx_char_cga(struct vgamode_s *vmode_g
232 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400233{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400234 u16 nbcols = GET_BDA(video_cols);
235 if (cp.x >= nbcols)
236 return;
237
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400238 u8 *fdata_g = vgafont8;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400239 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400240 u16 addr = (cp.x * bpp) + cp.y * 320;
Kevin O'Connor09262412009-05-25 11:44:11 -0400241 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400242 u8 i;
243 for (i = 0; i < 8; i++) {
244 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
245 if (i & 1)
246 dest_far += 0x2000;
247 u8 mask = 0x80;
248 if (bpp == 1) {
249 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400250 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400251 data = GET_FARVAR(SEG_CTEXT, *dest_far);
252 u8 j;
253 for (j = 0; j < 8; j++) {
254 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400255 if (ca.attr & 0x80)
256 data ^= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400257 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400258 data |= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400259 }
260 mask >>= 1;
261 }
262 SET_FARVAR(SEG_CTEXT, *dest_far, data);
263 } else {
264 while (mask > 0) {
265 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400266 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400267 data = GET_FARVAR(SEG_CTEXT, *dest_far);
268 u8 j;
269 for (j = 0; j < 4; j++) {
270 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400271 if (ca.attr & 0x80)
272 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400273 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400274 data |= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400275 }
276 mask >>= 1;
277 }
278 SET_FARVAR(SEG_CTEXT, *dest_far, data);
279 dest_far += 1;
280 }
281 }
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);
300 u8 mask = 0x80;
301 u8 j;
302 for (j = 0; j < 8; j++) {
303 u8 data = 0x00;
304 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400305 data = ca.attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400306 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
307 mask >>= 1;
308 }
309 }
310}
311
Kevin O'Connord3b38152009-05-26 00:05:37 -0400312static void
313write_text_char(struct vgamode_s *vmode_g
314 , struct cursorpos cp, struct carattr ca)
315{
316 // Get the dimensions
317 u16 nbrows = GET_BDA(video_rows) + 1;
318 u16 nbcols = GET_BDA(video_cols);
319
320 // Compute the address
321 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
322 + (cp.x + cp.y * nbcols) * 2);
323
324 if (ca.use_attr) {
325 u16 dummy = (ca.attr << 8) | ca.car;
326 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
327 } else {
328 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
329 }
330}
331
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400332void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400333vgafb_write_char(struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400334{
335 // Get the mode
336 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
337 if (!vmode_g)
338 return;
339
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400340 // FIXME gfx mode not complete
Kevin O'Connord3b38152009-05-26 00:05:37 -0400341 switch (GET_GLOBAL(vmode_g->memmodel)) {
342 case CTEXT:
343 case MTEXT:
344 write_text_char(vmode_g, cp, ca);
345 break;
346 case PLANAR4:
347 case PLANAR1:
348 write_gfx_char_pl4(vmode_g, cp, ca);
349 break;
350 case CGA:
351 write_gfx_char_cga(vmode_g, cp, ca);
352 break;
353 case LINEAR8:
354 write_gfx_char_lin(vmode_g, cp, ca);
355 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400356 }
357}
358
Kevin O'Connor09262412009-05-25 11:44:11 -0400359struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400360vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400361{
362 // Get the mode
363 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
364 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400365 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400366
Kevin O'Connord3b38152009-05-26 00:05:37 -0400367 if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
368 // FIXME gfx mode
369 dprintf(1, "Read char in graphics mode\n");
370 goto fail;
371 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400372
373 // Get the dimensions
374 u16 nbrows = GET_BDA(video_rows) + 1;
375 u16 nbcols = GET_BDA(video_cols);
376
Kevin O'Connord3b38152009-05-26 00:05:37 -0400377 // Compute the address
378 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
379 + (cp.x + cp.y * nbcols) * 2);
380 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
381 struct carattr ca = {v, v>>8, 0};
Kevin O'Connor09262412009-05-25 11:44:11 -0400382 return ca;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400383
384fail: ;
385 struct carattr ca2 = {0, 0, 0};
386 return ca2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400387}
388
389
390/****************************************************************
391 * Read/write pixels
392 ****************************************************************/
393
394void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400395vgafb_write_pixel(u8 color, u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400396{
397 // Get the mode
398 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
399 if (!vmode_g)
400 return;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400401 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400402 return;
403
404 u8 *addr_far, mask, attr, data;
405 switch (GET_GLOBAL(vmode_g->memmodel)) {
406 case PLANAR4:
407 case PLANAR1:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400408 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
409 mask = 0x80 >> (x & 0x07);
Kevin O'Connor414d0732009-05-31 22:42:04 -0400410 vgahw_grdc_write(0x08, mask);
411 vgahw_grdc_write(0x05, 0x02);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400412 data = GET_FARVAR(SEG_GRAPH, *addr_far);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400413 if (color & 0x80)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400414 vgahw_grdc_write(0x03, 0x18);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400415 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connor414d0732009-05-31 22:42:04 -0400416 vgahw_grdc_write(0x08, 0xff);
417 vgahw_grdc_write(0x05, 0x00);
418 vgahw_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400419 break;
420 case CGA:
421 if (GET_GLOBAL(vmode_g->pixbits) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400422 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400423 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400424 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
425 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400426 addr_far += 0x2000;
427 data = GET_FARVAR(SEG_CTEXT, *addr_far);
428 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400429 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
430 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400431 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400432 attr = (color & 0x01) << (7 - (x & 0x07));
433 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400434 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400435 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400436 data ^= attr;
437 } else {
438 data &= ~mask;
439 data |= attr;
440 }
441 SET_FARVAR(SEG_CTEXT, *addr_far, data);
442 break;
443 case LINEAR8:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400444 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
445 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400446 break;
447 }
448}
449
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400450u8
451vgafb_read_pixel(u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400452{
453 // Get the mode
454 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
455 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400456 return 0;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400457 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400458 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400459
460 u8 *addr_far, mask, attr=0, data, i;
461 switch (GET_GLOBAL(vmode_g->memmodel)) {
462 case PLANAR4:
463 case PLANAR1:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400464 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
465 mask = 0x80 >> (x & 0x07);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400466 attr = 0x00;
467 for (i = 0; i < 4; i++) {
Kevin O'Connor414d0732009-05-31 22:42:04 -0400468 vgahw_grdc_write(0x04, i);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400469 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
470 if (data > 0)
471 attr |= (0x01 << i);
472 }
473 break;
474 case CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400475 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
476 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400477 addr_far += 0x2000;
478 data = GET_FARVAR(SEG_CTEXT, *addr_far);
479 if (GET_GLOBAL(vmode_g->pixbits) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400480 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400481 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400482 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400483 break;
484 case LINEAR8:
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;
488 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400489 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400490}
491
492
493/****************************************************************
494 * Font loading
495 ****************************************************************/
496
497void
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400498vgafb_load_font(u16 seg, void *src_far, u16 count
499 , u16 start, u8 destflags, u8 fontsize)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400500{
501 get_font_access();
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400502 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
503 void *dest_far = (void*)(blockaddr + start*32);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400504 u16 i;
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400505 for (i = 0; i < count; i++)
506 memcpy_far(SEG_GRAPH, dest_far + i*32
507 , seg, src_far + i*fontsize, fontsize);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400508 release_font_access();
509}