|
|
1.1 root 1: // Code for manipulating VGA framebuffers.
2: //
3: // Copyright (C) 2009 Kevin O'Connor <[email protected]>
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:
12:
13: /****************************************************************
14: * Screen scrolling
15: ****************************************************************/
16:
17: static inline void *
18: memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
19: {
20: for (; lines; lines--, dst+=stride, src+=stride)
21: memcpy_far(seg, dst, seg, src, copylen);
22: return dst;
23: }
24:
25: static inline void
26: memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
27: {
28: for (; lines; lines--, dst+=stride)
29: memset_far(seg, dst, val, setlen);
30: }
31:
32: static inline void
33: memset16_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);
37: }
38:
39: static void
40: scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
41: , struct cursorpos ul, struct cursorpos lr)
42: {
43: struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
44: u8 cheight = GET_GLOBAL(vparam_g->cheight);
45: 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;
56: }
57: int cols = lr.x - ul.x + 1;
58: int rows = lr.y - ul.y + 1;
59: if (nblines < rows) {
60: vgahw_grdc_write(0x05, 0x01);
61: dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
62: , (rows - nblines) * cheight);
63: }
64: if (attr < 0)
65: attr = 0;
66: vgahw_grdc_write(0x05, 0x02);
67: memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
68: vgahw_grdc_write(0x05, 0x00);
69: }
70:
71: static void
72: scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
73: , struct cursorpos ul, struct cursorpos lr)
74: {
75: 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);
78: 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;
89: }
90: 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);
97: }
98: 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);
104: }
105:
106: static void
107: scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
108: , struct cursorpos ul, struct cursorpos lr)
109: {
110: u16 nbrows = GET_BDA(video_rows) + 1;
111: u16 nbcols = GET_BDA(video_cols);
112: 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;
123: }
124: 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);
134: }
135:
136: void
137: vgafb_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:
162: void
163: clear_screen(struct vgamode_s *vmode_g)
164: {
165: switch (GET_GLOBAL(vmode_g->memmodel)) {
166: case CTEXT:
167: case MTEXT:
168: memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
169: break;
170: case CGA:
171: memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
172: break;
173: default:
174: // XXX - old code gets/sets/restores sequ register 2 to 0xf -
175: // but it should always be 0xf anyway.
176: memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
177: }
178: }
179:
180:
181: /****************************************************************
182: * Read/write characters to screen
183: ****************************************************************/
184:
185: static void
186: write_gfx_char_pl4(struct vgamode_s *vmode_g
187: , struct cursorpos cp, struct carattr ca)
188: {
189: 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);
195: 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: }
206: u16 addr = cp.x + cp.y * cheight * nbcols;
207: u16 src = ca.car * cheight;
208: vgahw_sequ_write(0x02, 0x0f);
209: vgahw_grdc_write(0x05, 0x02);
210: if (ca.attr & 0x80)
211: vgahw_grdc_write(0x03, 0x18);
212: else
213: vgahw_grdc_write(0x03, 0x00);
214: 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;
220: vgahw_grdc_write(0x08, mask);
221: GET_FARVAR(SEG_GRAPH, *dest_far);
222: if (GET_GLOBAL(fdata_g[src + i]) & mask)
223: SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
224: else
225: SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
226: }
227: }
228: vgahw_grdc_write(0x08, 0xff);
229: vgahw_grdc_write(0x05, 0x00);
230: vgahw_grdc_write(0x03, 0x00);
231: }
232:
233: static void
234: write_gfx_char_cga(struct vgamode_s *vmode_g
235: , struct cursorpos cp, struct carattr ca)
236: {
237: u16 nbcols = GET_BDA(video_cols);
238: if (cp.x >= nbcols)
239: return;
240:
241: u8 *fdata_g = vgafont8;
242: u8 bpp = GET_GLOBAL(vmode_g->pixbits);
243: u16 addr = (cp.x * bpp) + cp.y * 320;
244: u16 src = ca.car * 8;
245: 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;
253: if (ca.attr & 0x80)
254: 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) {
258: if (ca.attr & 0x80)
259: data ^= (ca.attr & 0x01) << (7 - j);
260: else
261: data |= (ca.attr & 0x01) << (7 - j);
262: }
263: mask >>= 1;
264: }
265: SET_FARVAR(SEG_CTEXT, *dest_far, data);
266: } else {
267: while (mask > 0) {
268: u8 data = 0;
269: if (ca.attr & 0x80)
270: 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) {
274: if (ca.attr & 0x80)
275: data ^= (ca.attr & 0x03) << ((3 - j) * 2);
276: else
277: data |= (ca.attr & 0x03) << ((3 - j) * 2);
278: }
279: mask >>= 1;
280: }
281: SET_FARVAR(SEG_CTEXT, *dest_far, data);
282: dest_far += 1;
283: }
284: }
285: }
286: }
287:
288: static void
289: write_gfx_char_lin(struct vgamode_s *vmode_g
290: , struct cursorpos cp, struct carattr ca)
291: {
292: // Get the dimensions
293: u16 nbcols = GET_BDA(video_cols);
294: if (cp.x >= nbcols)
295: return;
296:
297: u8 *fdata_g = vgafont8;
298: u16 addr = cp.x * 8 + cp.y * nbcols * 64;
299: u16 src = ca.car * 8;
300: 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)
308: data = ca.attr;
309: SET_FARVAR(SEG_GRAPH, dest_far[j], data);
310: mask >>= 1;
311: }
312: }
313: }
314:
315: static void
316: write_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:
335: void
336: vgafb_write_char(struct cursorpos cp, struct carattr ca)
337: {
338: // Get the mode
339: struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
340: if (!vmode_g)
341: return;
342:
343: // FIXME gfx mode not complete
344: 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;
359: }
360: }
361:
362: struct carattr
363: vgafb_read_char(struct cursorpos cp)
364: {
365: // Get the mode
366: struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
367: if (!vmode_g)
368: goto fail;
369:
370: if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
371: // FIXME gfx mode
372: dprintf(1, "Read char in graphics mode\n");
373: goto fail;
374: }
375:
376: // Get the dimensions
377: u16 nbrows = GET_BDA(video_rows) + 1;
378: u16 nbcols = GET_BDA(video_cols);
379:
380: // 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};
385: return ca;
386:
387: fail: ;
388: struct carattr ca2 = {0, 0, 0};
389: return ca2;
390: }
391:
392:
393: /****************************************************************
394: * Read/write pixels
395: ****************************************************************/
396:
397: void
398: vgafb_write_pixel(u8 color, u16 x, u16 y)
399: {
400: // Get the mode
401: struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
402: if (!vmode_g)
403: return;
404: if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
405: return;
406:
407: u8 *addr_far, mask, attr, data;
408: switch (GET_GLOBAL(vmode_g->memmodel)) {
409: case PLANAR4:
410: case PLANAR1:
411: addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
412: mask = 0x80 >> (x & 0x07);
413: vgahw_grdc_write(0x08, mask);
414: vgahw_grdc_write(0x05, 0x02);
415: data = GET_FARVAR(SEG_GRAPH, *addr_far);
416: if (color & 0x80)
417: vgahw_grdc_write(0x03, 0x18);
418: SET_FARVAR(SEG_GRAPH, *addr_far, color);
419: vgahw_grdc_write(0x08, 0xff);
420: vgahw_grdc_write(0x05, 0x00);
421: vgahw_grdc_write(0x03, 0x00);
422: break;
423: case CGA:
424: if (GET_GLOBAL(vmode_g->pixbits) == 2)
425: addr_far = (void*)((x >> 2) + (y >> 1) * 80);
426: else
427: addr_far = (void*)((x >> 3) + (y >> 1) * 80);
428: if (y & 1)
429: addr_far += 0x2000;
430: data = GET_FARVAR(SEG_CTEXT, *addr_far);
431: if (GET_GLOBAL(vmode_g->pixbits) == 2) {
432: attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
433: mask = 0x03 << ((3 - (x & 0x03)) * 2);
434: } else {
435: attr = (color & 0x01) << (7 - (x & 0x07));
436: mask = 0x01 << (7 - (x & 0x07));
437: }
438: if (color & 0x80) {
439: data ^= attr;
440: } else {
441: data &= ~mask;
442: data |= attr;
443: }
444: SET_FARVAR(SEG_CTEXT, *addr_far, data);
445: break;
446: case LINEAR8:
447: addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
448: SET_FARVAR(SEG_GRAPH, *addr_far, color);
449: break;
450: }
451: }
452:
453: u8
454: vgafb_read_pixel(u16 x, u16 y)
455: {
456: // Get the mode
457: struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
458: if (!vmode_g)
459: return 0;
460: if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
461: return 0;
462:
463: u8 *addr_far, mask, attr=0, data, i;
464: switch (GET_GLOBAL(vmode_g->memmodel)) {
465: case PLANAR4:
466: case PLANAR1:
467: addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
468: mask = 0x80 >> (x & 0x07);
469: attr = 0x00;
470: for (i = 0; i < 4; i++) {
471: vgahw_grdc_write(0x04, i);
472: data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
473: if (data > 0)
474: attr |= (0x01 << i);
475: }
476: break;
477: case CGA:
478: addr_far = (void*)((x >> 2) + (y >> 1) * 80);
479: if (y & 1)
480: addr_far += 0x2000;
481: data = GET_FARVAR(SEG_CTEXT, *addr_far);
482: if (GET_GLOBAL(vmode_g->pixbits) == 2)
483: attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
484: else
485: attr = (data >> (7 - (x & 0x07))) & 0x01;
486: break;
487: case LINEAR8:
488: addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
489: attr = GET_FARVAR(SEG_GRAPH, *addr_far);
490: break;
491: }
492: return attr;
493: }
494:
495:
496: /****************************************************************
497: * Font loading
498: ****************************************************************/
499:
500: void
501: vgafb_load_font(u16 seg, void *src_far, u16 count
502: , u16 start, u8 destflags, u8 fontsize)
503: {
504: get_font_access();
505: u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
506: void *dest_far = (void*)(blockaddr + start*32);
507: u16 i;
508: for (i = 0; i < count; i++)
509: memcpy_far(SEG_GRAPH, dest_far + i*32
510: , seg, src_far + i*fontsize, fontsize);
511: release_font_access();
512: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.