blob: c9a257a20f7e760f5f019a1e7e797f3fa29377fd [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'Connore1e000b2011-12-31 03:30:40 -050010#include "vgabios.h" // find_vga_entry
Kevin O'Connor88ca7412011-12-31 04:24:20 -050011#include "stdvga.h" // stdvga_grdc_write
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040012
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040013
14/****************************************************************
15 * Screen scrolling
16 ****************************************************************/
17
Kevin O'Connor2c34f412009-05-31 15:25:14 -040018static inline void *
19memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040020{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040021 for (; lines; lines--, dst+=stride, src+=stride)
22 memcpy_far(seg, dst, seg, src, copylen);
23 return dst;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040024}
25
Kevin O'Connor2c34f412009-05-31 15:25:14 -040026static inline void
27memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040028{
Kevin O'Connor2c34f412009-05-31 15:25:14 -040029 for (; lines; lines--, dst+=stride)
30 memset_far(seg, dst, val, setlen);
31}
32
33static inline void
34memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
35{
36 for (; lines; lines--, dst+=stride)
37 memset16_far(seg, dst, val, setlen);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040038}
39
40static void
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040041scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
42 , struct cursorpos ul, struct cursorpos lr)
43{
Kevin O'Connor87233e92011-12-23 21:40:34 -050044 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040045 int stride = GET_BDA(video_cols);
46 void *src_far, *dest_far;
47 if (nblines >= 0) {
48 dest_far = (void*)(ul.y * cheight * stride + ul.x);
49 src_far = dest_far + nblines * cheight * stride;
50 } else {
51 // Scroll down
52 nblines = -nblines;
53 dest_far = (void*)(lr.y * cheight * stride + ul.x);
54 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 int cols = lr.x - ul.x + 1;
58 int rows = lr.y - ul.y + 1;
59 if (nblines < rows) {
Kevin O'Connor88ca7412011-12-31 04:24:20 -050060 stdvga_grdc_write(0x05, 0x01);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040061 dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
62 , (rows - nblines) * cheight);
63 }
64 if (attr < 0)
65 attr = 0;
Kevin O'Connor88ca7412011-12-31 04:24:20 -050066 stdvga_grdc_write(0x05, 0x02);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040067 memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
Kevin O'Connor88ca7412011-12-31 04:24:20 -050068 stdvga_grdc_write(0x05, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040069}
70
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040071static void
72scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
73 , struct cursorpos ul, struct cursorpos lr)
74{
Kevin O'Connor87233e92011-12-23 21:40:34 -050075 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040076 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040077 int stride = GET_BDA(video_cols) * bpp;
78 void *src_far, *dest_far;
79 if (nblines >= 0) {
80 dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
81 src_far = dest_far + nblines * cheight * stride;
82 } else {
83 // Scroll down
84 nblines = -nblines;
85 dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
86 src_far = dest_far - nblines * cheight * stride;
87 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040088 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040089 int cols = (lr.x - ul.x + 1) * bpp;
90 int rows = lr.y - ul.y + 1;
91 if (nblines < rows) {
92 memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
93 , stride, (rows - nblines) * cheight / 2);
94 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
95 , stride, (rows - nblines) * cheight / 2);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040096 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040097 if (attr < 0)
98 attr = 0;
99 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
100 , stride, nblines * cheight / 2);
101 memset_stride(SEG_CTEXT, dest_far, attr, cols
102 , stride, nblines * cheight / 2);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400103}
104
105static void
106scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
107 , struct cursorpos ul, struct cursorpos lr)
108{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400109 u16 nbrows = GET_BDA(video_rows) + 1;
110 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400111 void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
112 int stride = nbcols * 2;
113 if (nblines >= 0) {
114 dest_far += ul.y * stride + ul.x * 2;
115 src_far = dest_far + nblines * stride;
116 } else {
117 // Scroll down
118 nblines = -nblines;
119 dest_far += lr.y * stride + ul.x * 2;
120 src_far = dest_far - nblines * stride;
121 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400122 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400123 int cols = (lr.x - ul.x + 1) * 2;
124 int rows = lr.y - ul.y + 1;
125 u16 seg = GET_GLOBAL(vmode_g->sstart);
126 if (nblines < rows)
127 dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
128 , (rows - nblines));
129 if (attr < 0)
130 attr = 0x07;
131 attr = (attr << 8) | ' ';
132 memset16_stride(seg, dest_far, attr, cols, stride, nblines);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400133}
134
135void
136vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
137{
138 // Get the mode
139 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
140 if (!vmode_g)
141 return;
142
143 // FIXME gfx mode not complete
144 switch (GET_GLOBAL(vmode_g->memmodel)) {
145 case CTEXT:
146 case MTEXT:
147 scroll_text(vmode_g, nblines, attr, ul, lr);
148 break;
149 case PLANAR4:
150 case PLANAR1:
151 scroll_pl4(vmode_g, nblines, attr, ul, lr);
152 break;
153 case CGA:
154 scroll_cga(vmode_g, nblines, attr, ul, lr);
155 break;
156 default:
157 dprintf(1, "Scroll in graphics mode\n");
158 }
159}
160
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400161void
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400162clear_screen(struct vgamode_s *vmode_g)
163{
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400164 switch (GET_GLOBAL(vmode_g->memmodel)) {
165 case CTEXT:
166 case MTEXT:
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400167 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400168 break;
169 case CGA:
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400170 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400171 break;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400172 default:
173 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
174 // but it should always be 0xf anyway.
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400175 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
Kevin O'Connorae6e1c82009-05-31 01:09:30 -0400176 }
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400177}
178
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400179
180/****************************************************************
181 * Read/write characters to screen
182 ****************************************************************/
183
184static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400185write_gfx_char_pl4(struct vgamode_s *vmode_g
186 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400187{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400188 u16 nbcols = GET_BDA(video_cols);
189 if (cp.x >= nbcols)
190 return;
191
Kevin O'Connor87233e92011-12-23 21:40:34 -0500192 u8 cheight = GET_GLOBAL(vmode_g->cheight);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400193 u8 *fdata_g;
194 switch (cheight) {
195 case 14:
196 fdata_g = vgafont14;
197 break;
198 case 16:
199 fdata_g = vgafont16;
200 break;
201 default:
202 fdata_g = vgafont8;
203 }
Kevin O'Connor918b1562009-05-25 11:05:18 -0400204 u16 addr = cp.x + cp.y * cheight * nbcols;
Kevin O'Connor09262412009-05-25 11:44:11 -0400205 u16 src = ca.car * cheight;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500206 stdvga_sequ_write(0x02, 0x0f);
207 stdvga_grdc_write(0x05, 0x02);
Kevin O'Connor09262412009-05-25 11:44:11 -0400208 if (ca.attr & 0x80)
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500209 stdvga_grdc_write(0x03, 0x18);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400210 else
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500211 stdvga_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400212 u8 i;
213 for (i = 0; i < cheight; i++) {
214 u8 *dest_far = (void*)(addr + i * nbcols);
215 u8 j;
216 for (j = 0; j < 8; j++) {
217 u8 mask = 0x80 >> j;
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500218 stdvga_grdc_write(0x08, mask);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400219 GET_FARVAR(SEG_GRAPH, *dest_far);
220 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400221 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400222 else
223 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
224 }
225 }
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500226 stdvga_grdc_write(0x08, 0xff);
227 stdvga_grdc_write(0x05, 0x00);
228 stdvga_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400229}
230
231static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400232write_gfx_char_cga(struct vgamode_s *vmode_g
233 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400234{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400235 u16 nbcols = GET_BDA(video_cols);
236 if (cp.x >= nbcols)
237 return;
238
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400239 u8 *fdata_g = vgafont8;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400240 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400241 u16 addr = (cp.x * bpp) + cp.y * 320;
Kevin O'Connor09262412009-05-25 11:44:11 -0400242 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400243 u8 i;
244 for (i = 0; i < 8; i++) {
245 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
246 if (i & 1)
247 dest_far += 0x2000;
248 u8 mask = 0x80;
249 if (bpp == 1) {
250 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400251 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400252 data = GET_FARVAR(SEG_CTEXT, *dest_far);
253 u8 j;
254 for (j = 0; j < 8; j++) {
255 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400256 if (ca.attr & 0x80)
257 data ^= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400258 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400259 data |= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400260 }
261 mask >>= 1;
262 }
263 SET_FARVAR(SEG_CTEXT, *dest_far, data);
264 } else {
265 while (mask > 0) {
266 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400267 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400268 data = GET_FARVAR(SEG_CTEXT, *dest_far);
269 u8 j;
270 for (j = 0; j < 4; j++) {
271 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400272 if (ca.attr & 0x80)
273 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400274 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400275 data |= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400276 }
277 mask >>= 1;
278 }
279 SET_FARVAR(SEG_CTEXT, *dest_far, data);
280 dest_far += 1;
281 }
282 }
283 }
284}
285
286static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400287write_gfx_char_lin(struct vgamode_s *vmode_g
288 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400289{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400290 // Get the dimensions
291 u16 nbcols = GET_BDA(video_cols);
292 if (cp.x >= nbcols)
293 return;
294
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400295 u8 *fdata_g = vgafont8;
Kevin O'Connor918b1562009-05-25 11:05:18 -0400296 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
Kevin O'Connor09262412009-05-25 11:44:11 -0400297 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400298 u8 i;
299 for (i = 0; i < 8; i++) {
300 u8 *dest_far = (void*)(addr + i * nbcols * 8);
301 u8 mask = 0x80;
302 u8 j;
303 for (j = 0; j < 8; j++) {
304 u8 data = 0x00;
305 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400306 data = ca.attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400307 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
308 mask >>= 1;
309 }
310 }
311}
312
Kevin O'Connord3b38152009-05-26 00:05:37 -0400313static void
314write_text_char(struct vgamode_s *vmode_g
315 , struct cursorpos cp, struct carattr ca)
316{
317 // Get the dimensions
318 u16 nbrows = GET_BDA(video_rows) + 1;
319 u16 nbcols = GET_BDA(video_cols);
320
321 // Compute the address
322 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
323 + (cp.x + cp.y * nbcols) * 2);
324
325 if (ca.use_attr) {
326 u16 dummy = (ca.attr << 8) | ca.car;
327 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
328 } else {
329 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
330 }
331}
332
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400333void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400334vgafb_write_char(struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400335{
336 // Get the mode
337 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
338 if (!vmode_g)
339 return;
340
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400341 // FIXME gfx mode not complete
Kevin O'Connord3b38152009-05-26 00:05:37 -0400342 switch (GET_GLOBAL(vmode_g->memmodel)) {
343 case CTEXT:
344 case MTEXT:
345 write_text_char(vmode_g, cp, ca);
346 break;
347 case PLANAR4:
348 case PLANAR1:
349 write_gfx_char_pl4(vmode_g, cp, ca);
350 break;
351 case CGA:
352 write_gfx_char_cga(vmode_g, cp, ca);
353 break;
354 case LINEAR8:
355 write_gfx_char_lin(vmode_g, cp, ca);
356 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400357 }
358}
359
Kevin O'Connor09262412009-05-25 11:44:11 -0400360struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400361vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400362{
363 // Get the mode
364 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
365 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400366 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400367
Kevin O'Connord3b38152009-05-26 00:05:37 -0400368 if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
369 // FIXME gfx mode
370 dprintf(1, "Read char in graphics mode\n");
371 goto fail;
372 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400373
374 // Get the dimensions
375 u16 nbrows = GET_BDA(video_rows) + 1;
376 u16 nbcols = GET_BDA(video_cols);
377
Kevin O'Connord3b38152009-05-26 00:05:37 -0400378 // Compute the address
379 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
380 + (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
399 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
400 if (!vmode_g)
401 return;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400402 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400403 return;
404
405 u8 *addr_far, mask, attr, data;
406 switch (GET_GLOBAL(vmode_g->memmodel)) {
407 case PLANAR4:
408 case PLANAR1:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400409 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
410 mask = 0x80 >> (x & 0x07);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500411 stdvga_grdc_write(0x08, mask);
412 stdvga_grdc_write(0x05, 0x02);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400413 data = GET_FARVAR(SEG_GRAPH, *addr_far);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400414 if (color & 0x80)
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500415 stdvga_grdc_write(0x03, 0x18);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400416 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500417 stdvga_grdc_write(0x08, 0xff);
418 stdvga_grdc_write(0x05, 0x00);
419 stdvga_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400420 break;
421 case CGA:
422 if (GET_GLOBAL(vmode_g->pixbits) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400423 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400424 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400425 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
426 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400427 addr_far += 0x2000;
428 data = GET_FARVAR(SEG_CTEXT, *addr_far);
429 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400430 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
431 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400432 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400433 attr = (color & 0x01) << (7 - (x & 0x07));
434 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400435 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400436 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400437 data ^= attr;
438 } else {
439 data &= ~mask;
440 data |= attr;
441 }
442 SET_FARVAR(SEG_CTEXT, *addr_far, data);
443 break;
444 case LINEAR8:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400445 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
446 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400447 break;
448 }
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
455 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
456 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400457 return 0;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400458 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400459 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400460
461 u8 *addr_far, mask, attr=0, data, i;
462 switch (GET_GLOBAL(vmode_g->memmodel)) {
463 case PLANAR4:
464 case PLANAR1:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400465 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
466 mask = 0x80 >> (x & 0x07);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400467 attr = 0x00;
468 for (i = 0; i < 4; i++) {
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500469 stdvga_grdc_write(0x04, i);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400470 data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
471 if (data > 0)
472 attr |= (0x01 << i);
473 }
474 break;
475 case CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400476 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
477 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400478 addr_far += 0x2000;
479 data = GET_FARVAR(SEG_CTEXT, *addr_far);
480 if (GET_GLOBAL(vmode_g->pixbits) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400481 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400482 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400483 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400484 break;
485 case LINEAR8:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400486 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400487 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
488 break;
489 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400490 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400491}
492
493
494/****************************************************************
495 * Font loading
496 ****************************************************************/
497
498void
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400499vgafb_load_font(u16 seg, void *src_far, u16 count
500 , u16 start, u8 destflags, u8 fontsize)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400501{
502 get_font_access();
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400503 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
504 void *dest_far = (void*)(blockaddr + start*32);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400505 u16 i;
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400506 for (i = 0; i < count; i++)
507 memcpy_far(SEG_GRAPH, dest_far + i*32
508 , seg, src_far + i*fontsize, fontsize);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400509 release_font_access();
510}