blob: f2212d5af8ce9f8712405298ab804b48934b4691 [file] [log] [blame]
Kevin O'Connor27129d02016-08-04 16:25:33 -04001// Virtual software based cursor support
2//
3// Copyright (C) 2014-2016 Kevin O'Connor <kevin@koconnor.net>
4//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
7#include "biosvar.h" // GET_BDA
Kevin O'Connor774f5cd2016-08-04 17:02:16 -04008#include "bregs.h" // struct bregs
Kevin O'Connor0397e802016-08-04 17:53:45 -04009#include "vgabios.h" // get_cursor_pos
10#include "vgafb.h" // handle_gfx_op
Kevin O'Connor2f2ec112016-08-05 11:14:58 -040011#include "vgautil.h" // swcursor_check_event
Kevin O'Connor27129d02016-08-04 16:25:33 -040012
13// Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
14static void
15gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
16{
17 u16 cursor_type = get_cursor_shape();
18 u8 start = cursor_type >> 8, end = cursor_type & 0xff;
19 struct gfx_op op;
20 init_gfx_op(&op, vmode_g);
21 op.x = cp.x * 8;
22 int cheight = GET_BDA(char_height);
23 op.y = cp.y * cheight + start;
24
25 int i;
26 for (i = start; i < cheight && i <= end; i++, op.y++) {
27 op.op = GO_READ8;
28 handle_gfx_op(&op);
29 int j;
30 for (j = 0; j < 8; j++)
31 op.pixels[j] ^= 0x07;
32 op.op = GO_WRITE8;
33 handle_gfx_op(&op);
34 }
35}
36
37// Draw/undraw a cursor on the screen
Kevin O'Connor774f5cd2016-08-04 17:02:16 -040038static void
39set_swcursor(int enable)
Kevin O'Connor27129d02016-08-04 16:25:33 -040040{
Kevin O'Connor27129d02016-08-04 16:25:33 -040041 u8 flags = GET_BDA_EXT(flags);
42 if (!!(flags & BF_SWCURSOR) == enable)
43 // Already in requested mode.
44 return;
45 struct vgamode_s *vmode_g = get_current_mode();
46 if (!vmode_g)
47 return;
48 struct cursorpos cp = get_cursor_pos(GET_BDA(video_page));
49 if (cp.x >= GET_BDA(video_cols) || cp.y > GET_BDA(video_rows)
50 || GET_BDA(cursor_type) >= 0x2000)
51 // Cursor not visible
52 return;
53
54 SET_BDA_EXT(flags, (flags & ~BF_SWCURSOR) | (enable ? BF_SWCURSOR : 0));
55
56 if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
57 gfx_set_swcursor(vmode_g, enable, cp);
58 return;
59 }
60
61 // In text mode, swap foreground and background attributes for cursor
62 void *dest_far = text_address(cp) + 1;
63 u8 attr = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far);
64 attr = (attr >> 4) | (attr << 4);
65 SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, attr);
66}
Kevin O'Connor774f5cd2016-08-04 17:02:16 -040067
68// Disable virtual cursor if a vgabios call accesses the framebuffer
69void
70swcursor_pre_handle10(struct bregs *regs)
71{
72 if (!vga_emulate_text())
73 return;
74 switch (regs->ah) {
75 case 0x4f:
76 if (!CONFIG_VGA_VBE || regs->al != 0x02)
77 break;
78 // NO BREAK
79 case 0x00 ... 0x02:
80 case 0x05 ... 0x0e:
81 case 0x13:
82 set_swcursor(0);
83 break;
84 default:
85 break;
86 }
87}
88
89// Called by periodic (18.2hz) timer
90void
91swcursor_check_event(void)
92{
93 if (!vga_emulate_text())
94 return;
95 set_swcursor(GET_BDA(timer_counter) % 18 < 9);
96}