blob: 866f7f8e11c50d460cacfb0498b0476268ece803 [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'Connor217f2bc2009-05-31 00:46:47 -040043 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
44 u8 cheight = GET_GLOBAL(vparam_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'Connor414d0732009-05-31 22:42:04 -040060 vgahw_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'Connor414d0732009-05-31 22:42:04 -040066 vgahw_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'Connor414d0732009-05-31 22:42:04 -040068 vgahw_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'Connor217f2bc2009-05-31 00:46:47 -040075 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
76 u8 cheight = GET_GLOBAL(vparam_g->cheight);
77 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
Kevin O'Connor2c34f412009-05-31 15:25:14 -040078 int stride = GET_BDA(video_cols) * bpp;
79 void *src_far, *dest_far;
80 if (nblines >= 0) {
81 dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
82 src_far = dest_far + nblines * cheight * stride;
83 } else {
84 // Scroll down
85 nblines = -nblines;
86 dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
87 src_far = dest_far - nblines * cheight * stride;
88 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040089 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040090 int cols = (lr.x - ul.x + 1) * bpp;
91 int rows = lr.y - ul.y + 1;
92 if (nblines < rows) {
93 memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
94 , stride, (rows - nblines) * cheight / 2);
95 dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
96 , stride, (rows - nblines) * cheight / 2);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -040097 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -040098 if (attr < 0)
99 attr = 0;
100 memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
101 , stride, nblines * cheight / 2);
102 memset_stride(SEG_CTEXT, dest_far, attr, cols
103 , stride, nblines * cheight / 2);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400104}
105
106static void
107scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
108 , struct cursorpos ul, struct cursorpos lr)
109{
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400110 u16 nbrows = GET_BDA(video_rows) + 1;
111 u16 nbcols = GET_BDA(video_cols);
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400112 void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
113 int stride = nbcols * 2;
114 if (nblines >= 0) {
115 dest_far += ul.y * stride + ul.x * 2;
116 src_far = dest_far + nblines * stride;
117 } else {
118 // Scroll down
119 nblines = -nblines;
120 dest_far += lr.y * stride + ul.x * 2;
121 src_far = dest_far - nblines * stride;
122 stride = -stride;
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400123 }
Kevin O'Connor2c34f412009-05-31 15:25:14 -0400124 int cols = (lr.x - ul.x + 1) * 2;
125 int rows = lr.y - ul.y + 1;
126 u16 seg = GET_GLOBAL(vmode_g->sstart);
127 if (nblines < rows)
128 dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
129 , (rows - nblines));
130 if (attr < 0)
131 attr = 0x07;
132 attr = (attr << 8) | ' ';
133 memset16_stride(seg, dest_far, attr, cols, stride, nblines);
Kevin O'Connor217f2bc2009-05-31 00:46:47 -0400134}
135
136void
137vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
138{
139 // Get the mode
140 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
141 if (!vmode_g)
142 return;
143
144 // FIXME gfx mode not complete
145 switch (GET_GLOBAL(vmode_g->memmodel)) {
146 case CTEXT:
147 case MTEXT:
148 scroll_text(vmode_g, nblines, attr, ul, lr);
149 break;
150 case PLANAR4:
151 case PLANAR1:
152 scroll_pl4(vmode_g, nblines, attr, ul, lr);
153 break;
154 case CGA:
155 scroll_cga(vmode_g, nblines, attr, ul, lr);
156 break;
157 default:
158 dprintf(1, "Scroll in graphics mode\n");
159 }
160}
161
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400162void
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400163clear_screen(struct vgamode_s *vmode_g)
164{
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400165 switch (GET_GLOBAL(vmode_g->memmodel)) {
166 case CTEXT:
167 case MTEXT:
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400168 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400169 break;
170 case CGA:
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400171 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400172 break;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400173 default:
174 // XXX - old code gets/sets/restores sequ register 2 to 0xf -
175 // but it should always be 0xf anyway.
Kevin O'Connore4145ad2009-05-31 00:53:18 -0400176 memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
Kevin O'Connorae6e1c82009-05-31 01:09:30 -0400177 }
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400178}
179
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400180
181/****************************************************************
182 * Read/write characters to screen
183 ****************************************************************/
184
185static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400186write_gfx_char_pl4(struct vgamode_s *vmode_g
187 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400188{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400189 u16 nbcols = GET_BDA(video_cols);
190 if (cp.x >= nbcols)
191 return;
192
193 struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
194 u8 cheight = GET_GLOBAL(vparam_g->cheight);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400195 u8 *fdata_g;
196 switch (cheight) {
197 case 14:
198 fdata_g = vgafont14;
199 break;
200 case 16:
201 fdata_g = vgafont16;
202 break;
203 default:
204 fdata_g = vgafont8;
205 }
Kevin O'Connor918b1562009-05-25 11:05:18 -0400206 u16 addr = cp.x + cp.y * cheight * nbcols;
Kevin O'Connor09262412009-05-25 11:44:11 -0400207 u16 src = ca.car * cheight;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400208 vgahw_sequ_write(0x02, 0x0f);
209 vgahw_grdc_write(0x05, 0x02);
Kevin O'Connor09262412009-05-25 11:44:11 -0400210 if (ca.attr & 0x80)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400211 vgahw_grdc_write(0x03, 0x18);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400212 else
Kevin O'Connor414d0732009-05-31 22:42:04 -0400213 vgahw_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400214 u8 i;
215 for (i = 0; i < cheight; i++) {
216 u8 *dest_far = (void*)(addr + i * nbcols);
217 u8 j;
218 for (j = 0; j < 8; j++) {
219 u8 mask = 0x80 >> j;
Kevin O'Connor414d0732009-05-31 22:42:04 -0400220 vgahw_grdc_write(0x08, mask);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400221 GET_FARVAR(SEG_GRAPH, *dest_far);
222 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400223 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400224 else
225 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
226 }
227 }
Kevin O'Connor414d0732009-05-31 22:42:04 -0400228 vgahw_grdc_write(0x08, 0xff);
229 vgahw_grdc_write(0x05, 0x00);
230 vgahw_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400231}
232
233static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400234write_gfx_char_cga(struct vgamode_s *vmode_g
235 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400236{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400237 u16 nbcols = GET_BDA(video_cols);
238 if (cp.x >= nbcols)
239 return;
240
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400241 u8 *fdata_g = vgafont8;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400242 u8 bpp = GET_GLOBAL(vmode_g->pixbits);
Kevin O'Connor918b1562009-05-25 11:05:18 -0400243 u16 addr = (cp.x * bpp) + cp.y * 320;
Kevin O'Connor09262412009-05-25 11:44:11 -0400244 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400245 u8 i;
246 for (i = 0; i < 8; i++) {
247 u8 *dest_far = (void*)(addr + (i >> 1) * 80);
248 if (i & 1)
249 dest_far += 0x2000;
250 u8 mask = 0x80;
251 if (bpp == 1) {
252 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400253 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400254 data = GET_FARVAR(SEG_CTEXT, *dest_far);
255 u8 j;
256 for (j = 0; j < 8; j++) {
257 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400258 if (ca.attr & 0x80)
259 data ^= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400260 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400261 data |= (ca.attr & 0x01) << (7 - j);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400262 }
263 mask >>= 1;
264 }
265 SET_FARVAR(SEG_CTEXT, *dest_far, data);
266 } else {
267 while (mask > 0) {
268 u8 data = 0;
Kevin O'Connor09262412009-05-25 11:44:11 -0400269 if (ca.attr & 0x80)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400270 data = GET_FARVAR(SEG_CTEXT, *dest_far);
271 u8 j;
272 for (j = 0; j < 4; j++) {
273 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
Kevin O'Connor09262412009-05-25 11:44:11 -0400274 if (ca.attr & 0x80)
275 data ^= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400276 else
Kevin O'Connor09262412009-05-25 11:44:11 -0400277 data |= (ca.attr & 0x03) << ((3 - j) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400278 }
279 mask >>= 1;
280 }
281 SET_FARVAR(SEG_CTEXT, *dest_far, data);
282 dest_far += 1;
283 }
284 }
285 }
286}
287
288static void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400289write_gfx_char_lin(struct vgamode_s *vmode_g
290 , struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400291{
Kevin O'Connord3b38152009-05-26 00:05:37 -0400292 // Get the dimensions
293 u16 nbcols = GET_BDA(video_cols);
294 if (cp.x >= nbcols)
295 return;
296
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400297 u8 *fdata_g = vgafont8;
Kevin O'Connor918b1562009-05-25 11:05:18 -0400298 u16 addr = cp.x * 8 + cp.y * nbcols * 64;
Kevin O'Connor09262412009-05-25 11:44:11 -0400299 u16 src = ca.car * 8;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400300 u8 i;
301 for (i = 0; i < 8; i++) {
302 u8 *dest_far = (void*)(addr + i * nbcols * 8);
303 u8 mask = 0x80;
304 u8 j;
305 for (j = 0; j < 8; j++) {
306 u8 data = 0x00;
307 if (GET_GLOBAL(fdata_g[src + i]) & mask)
Kevin O'Connor09262412009-05-25 11:44:11 -0400308 data = ca.attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400309 SET_FARVAR(SEG_GRAPH, dest_far[j], data);
310 mask >>= 1;
311 }
312 }
313}
314
Kevin O'Connord3b38152009-05-26 00:05:37 -0400315static void
316write_text_char(struct vgamode_s *vmode_g
317 , struct cursorpos cp, struct carattr ca)
318{
319 // Get the dimensions
320 u16 nbrows = GET_BDA(video_rows) + 1;
321 u16 nbcols = GET_BDA(video_cols);
322
323 // Compute the address
324 void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
325 + (cp.x + cp.y * nbcols) * 2);
326
327 if (ca.use_attr) {
328 u16 dummy = (ca.attr << 8) | ca.car;
329 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
330 } else {
331 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
332 }
333}
334
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400335void
Kevin O'Connord3b38152009-05-26 00:05:37 -0400336vgafb_write_char(struct cursorpos cp, struct carattr ca)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400337{
338 // Get the mode
339 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
340 if (!vmode_g)
341 return;
342
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400343 // FIXME gfx mode not complete
Kevin O'Connord3b38152009-05-26 00:05:37 -0400344 switch (GET_GLOBAL(vmode_g->memmodel)) {
345 case CTEXT:
346 case MTEXT:
347 write_text_char(vmode_g, cp, ca);
348 break;
349 case PLANAR4:
350 case PLANAR1:
351 write_gfx_char_pl4(vmode_g, cp, ca);
352 break;
353 case CGA:
354 write_gfx_char_cga(vmode_g, cp, ca);
355 break;
356 case LINEAR8:
357 write_gfx_char_lin(vmode_g, cp, ca);
358 break;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400359 }
360}
361
Kevin O'Connor09262412009-05-25 11:44:11 -0400362struct carattr
Kevin O'Connord3b38152009-05-26 00:05:37 -0400363vgafb_read_char(struct cursorpos cp)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400364{
365 // Get the mode
366 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
367 if (!vmode_g)
Kevin O'Connor09262412009-05-25 11:44:11 -0400368 goto fail;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400369
Kevin O'Connord3b38152009-05-26 00:05:37 -0400370 if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
371 // FIXME gfx mode
372 dprintf(1, "Read char in graphics mode\n");
373 goto fail;
374 }
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400375
376 // Get the dimensions
377 u16 nbrows = GET_BDA(video_rows) + 1;
378 u16 nbcols = GET_BDA(video_cols);
379
Kevin O'Connord3b38152009-05-26 00:05:37 -0400380 // Compute the address
381 u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
382 + (cp.x + cp.y * nbcols) * 2);
383 u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
384 struct carattr ca = {v, v>>8, 0};
Kevin O'Connor09262412009-05-25 11:44:11 -0400385 return ca;
Kevin O'Connord3b38152009-05-26 00:05:37 -0400386
387fail: ;
388 struct carattr ca2 = {0, 0, 0};
389 return ca2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400390}
391
392
393/****************************************************************
394 * Read/write pixels
395 ****************************************************************/
396
397void
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400398vgafb_write_pixel(u8 color, u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400399{
400 // Get the mode
401 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
402 if (!vmode_g)
403 return;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400404 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400405 return;
406
407 u8 *addr_far, mask, attr, data;
408 switch (GET_GLOBAL(vmode_g->memmodel)) {
409 case PLANAR4:
410 case PLANAR1:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400411 addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
412 mask = 0x80 >> (x & 0x07);
Kevin O'Connor414d0732009-05-31 22:42:04 -0400413 vgahw_grdc_write(0x08, mask);
414 vgahw_grdc_write(0x05, 0x02);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400415 data = GET_FARVAR(SEG_GRAPH, *addr_far);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400416 if (color & 0x80)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400417 vgahw_grdc_write(0x03, 0x18);
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400418 SET_FARVAR(SEG_GRAPH, *addr_far, color);
Kevin O'Connor414d0732009-05-31 22:42:04 -0400419 vgahw_grdc_write(0x08, 0xff);
420 vgahw_grdc_write(0x05, 0x00);
421 vgahw_grdc_write(0x03, 0x00);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400422 break;
423 case CGA:
424 if (GET_GLOBAL(vmode_g->pixbits) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400425 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400426 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400427 addr_far = (void*)((x >> 3) + (y >> 1) * 80);
428 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400429 addr_far += 0x2000;
430 data = GET_FARVAR(SEG_CTEXT, *addr_far);
431 if (GET_GLOBAL(vmode_g->pixbits) == 2) {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400432 attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
433 mask = 0x03 << ((3 - (x & 0x03)) * 2);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400434 } else {
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400435 attr = (color & 0x01) << (7 - (x & 0x07));
436 mask = 0x01 << (7 - (x & 0x07));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400437 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400438 if (color & 0x80) {
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400439 data ^= attr;
440 } else {
441 data &= ~mask;
442 data |= attr;
443 }
444 SET_FARVAR(SEG_CTEXT, *addr_far, data);
445 break;
446 case LINEAR8:
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;
450 }
451}
452
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400453u8
454vgafb_read_pixel(u16 x, u16 y)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400455{
456 // Get the mode
457 struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
458 if (!vmode_g)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400459 return 0;
Kevin O'Connore4f220f2009-05-25 23:37:13 -0400460 if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400461 return 0;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400462
463 u8 *addr_far, mask, attr=0, data, i;
464 switch (GET_GLOBAL(vmode_g->memmodel)) {
465 case PLANAR4:
466 case PLANAR1:
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'Connor414d0732009-05-31 22:42:04 -0400471 vgahw_grdc_write(0x04, 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 }
476 break;
477 case CGA:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400478 addr_far = (void*)((x >> 2) + (y >> 1) * 80);
479 if (y & 1)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400480 addr_far += 0x2000;
481 data = GET_FARVAR(SEG_CTEXT, *addr_far);
482 if (GET_GLOBAL(vmode_g->pixbits) == 2)
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400483 attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400484 else
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400485 attr = (data >> (7 - (x & 0x07))) & 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400486 break;
487 case LINEAR8:
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400488 addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400489 attr = GET_FARVAR(SEG_GRAPH, *addr_far);
490 break;
491 }
Kevin O'Connor227a2bb2009-05-31 22:00:20 -0400492 return attr;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400493}
494
495
496/****************************************************************
497 * Font loading
498 ****************************************************************/
499
500void
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400501vgafb_load_font(u16 seg, void *src_far, u16 count
502 , u16 start, u8 destflags, u8 fontsize)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400503{
504 get_font_access();
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400505 u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
506 void *dest_far = (void*)(blockaddr + start*32);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400507 u16 i;
Kevin O'Connordeb9cb92009-05-25 09:06:50 -0400508 for (i = 0; i < count; i++)
509 memcpy_far(SEG_GRAPH, dest_far + i*32
510 , seg, src_far + i*fontsize, fontsize);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400511 release_font_access();
512}