int
cbvga_set_mode(struct vgamode_s *vmode_g, int flags)
{
- MASK_BDA_EXT(flags, BF_EMULATE_TEXT
- , (vmode_g == &CBemulinfo) ? BF_EMULATE_TEXT : 0);
+ u8 emul = vmode_g == &CBemulinfo || GET_GLOBAL(CBmode) == 0x03;
+ MASK_BDA_EXT(flags, BF_EMULATE_TEXT, emul ? BF_EMULATE_TEXT : 0);
if (!(flags & MF_NOCLEARMEM)) {
if (GET_GLOBAL(CBmodeinfo.memmodel) == MM_TEXT) {
memset16_far(SEG_CTEXT, (void*)0, 0x0720, 80*25*2);
}
// Determine cursor shape (taking into account possible cursor scaling)
-static u16
+u16
get_cursor_shape(void)
{
u16 cursor_type = GET_BDA(cursor_type);
static void
set_cursor_shape(u16 cursor_type)
{
+ vgafb_set_swcursor(0);
SET_BDA(cursor_type, cursor_type);
if (CONFIG_VGA_STDVGA_PORTS)
stdvga_set_cursor_shape(get_cursor_shape());
if (page > 7)
return;
+ vgafb_set_swcursor(0);
+
// Bios cursor pos
SET_BDA(cursor_pos[page], (y << 8) | x);
stdvga_set_cursor_pos((int)text_address(cp));
}
-static struct cursorpos
+struct cursorpos
get_cursor_pos(u8 page)
{
if (page == 0xff)
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
+
// Calculate memory address of start of page
struct cursorpos cp = {0, 0, page};
int address = (int)text_address(cp);
if (!vmode_g)
return VBE_RETURN_STATUS_FAILED;
+ vgafb_set_swcursor(0);
+
int ret = vgahw_set_mode(vmode_g, flags);
if (ret)
return ret;
int cwidth = GET_GLOBAL(vmode_g->cwidth);
SET_BDA(video_cols, width / cwidth);
SET_BDA(video_rows, (height / cheight) - 1);
- SET_BDA(cursor_type, 0x0000);
+ SET_BDA(cursor_type, vga_emulate_text() ? 0x0607 : 0x0000);
}
SET_BDA(video_pagesize, calc_page_size(memmodel, width, height));
SET_BDA(crtc_address, CONFIG_VGA_STDVGA_PORTS ? stdvga_get_crtc() : 0);
#define BF_PM_MASK 0x0f
#define BF_EMULATE_TEXT 0x10
+#define BF_SWCURSOR 0x20
#define GET_BDA_EXT(var) \
GET_FARVAR(SEG_BDA, ((struct vga_bda_s *)VGA_CUSTOM_BDA)->var)
};
int vga_bpp(struct vgamode_s *vmode_g);
u16 calc_page_size(u8 memmodel, u16 width, u16 height);
+u16 get_cursor_shape(void);
+struct cursorpos get_cursor_pos(u8 page);
int bda_save_restore(int cmd, u16 seg, void *data);
struct vgamode_s *get_current_mode(void);
int vga_set_mode(int mode, int flags);
struct carattr vgafb_read_char(struct cursorpos cp);
void vgafb_write_pixel(u8 color, u16 x, u16 y);
u8 vgafb_read_pixel(u16 x, u16 y);
+void vgafb_set_swcursor(int enable);
// vbe.c
extern u32 VBE_total_memory;
pushl BREGS_code(%eax)
RESTOREBREGS_DSEAX
iretw
+
+ // Timer irq handling
+ DECLFUNC entry_timer_hook
+entry_timer_hook:
+ ENTRY handle_timer_hook
+ ljmpw *%cs:Timer_Hook_Resume
+
+ // Timer irq handling on extra stack
+ DECLFUNC entry_timer_hook_extrastack
+entry_timer_hook_extrastack:
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movw %cs:ExtraStackSeg, %ds
+ movl $(CONFIG_VGA_EXTRA_STACK_SIZE-BREGS_size-8), %eax
+ SAVEBREGS_POP_DSEAX
+ movl %esp, BREGS_size(%eax)
+ movw %ss, BREGS_size+4(%eax)
+
+ movw %ds, %dx // Setup %ss/%esp and call function
+ movw %dx, %ss
+ movl %eax, %esp
+ calll handle_timer_hook
+
+ movl %esp, %eax // Restore registers and return
+ movw BREGS_size+4(%eax), %ss
+ movl BREGS_size(%eax), %esp
+ RESTOREBREGS_DSEAX
+ ljmpw *%cs:Timer_Hook_Resume
}
}
+// Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
+void
+gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
+{
+ u16 cursor_type = get_cursor_shape();
+ u8 start = cursor_type >> 8, end = cursor_type & 0xff;
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = cp.x * 8;
+ int cheight = GET_BDA(char_height);
+ op.y = cp.y * cheight + start;
+
+ int i;
+ for (i = start; i < cheight && i <= end; i++, op.y++) {
+ op.op = GO_READ8;
+ handle_gfx_op(&op);
+ int j;
+ for (j = 0; j < 8; j++)
+ op.pixels[j] ^= 0x07;
+ op.op = GO_WRITE8;
+ handle_gfx_op(&op);
+ }
+}
+
// Set the pixel at the given position.
void
vgafb_write_pixel(u8 color, u16 x, u16 y)
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
struct gfx_op op;
init_gfx_op(&op, vmode_g);
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return 0;
+ vgafb_set_swcursor(0);
struct gfx_op op;
init_gfx_op(&op, vmode_g);
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
gfx_move_chars(vmode_g, dest, src, movesize);
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
gfx_clear_chars(vmode_g, dest, ca, clearsize);
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
return;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
gfx_write_char(vmode_g, cp, ca);
struct vgamode_s *vmode_g = get_current_mode();
if (!vmode_g)
goto fail;
+ vgafb_set_swcursor(0);
if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
// FIXME gfx mode
struct carattr ca2 = {0, 0, 0};
return ca2;
}
+
+// Draw/undraw a cursor on the screen
+void
+vgafb_set_swcursor(int enable)
+{
+ if (!vga_emulate_text())
+ return;
+ u8 flags = GET_BDA_EXT(flags);
+ if (!!(flags & BF_SWCURSOR) == enable)
+ // Already in requested mode.
+ return;
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ struct cursorpos cp = get_cursor_pos(0xff);
+ if (cp.x >= GET_BDA(video_cols) || cp.y > GET_BDA(video_rows)
+ || GET_BDA(cursor_type) >= 0x2000)
+ // Cursor not visible
+ return;
+
+ SET_BDA_EXT(flags, (flags & ~BF_SWCURSOR) | (enable ? BF_SWCURSOR : 0));
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
+ gfx_set_swcursor(vmode_g, enable, cp);
+ return;
+ }
+
+ // In text mode, swap foreground and background attributes for cursor
+ void *dest_far = text_address(cp) + 1;
+ u8 attr = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far);
+ attr = (attr >> 4) | (attr << 4);
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, attr);
+}
}
+/****************************************************************
+ * Timer hook
+ ****************************************************************/
+
+struct segoff_s Timer_Hook_Resume VAR16 VISIBLE16;
+
+void VISIBLE16
+handle_timer_hook(void)
+{
+ if (!vga_emulate_text())
+ return;
+ vgafb_set_swcursor(GET_BDA(timer_counter) % 18 < 9);
+}
+
+static void
+hook_timer_irq(void)
+{
+ if (!CONFIG_VGA_EMULATE_TEXT)
+ return;
+ extern void entry_timer_hook(void);
+ extern void entry_timer_hook_extrastack(void);
+ struct segoff_s oldirq = GET_IVT(0x08);
+ struct segoff_s newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook);
+ if (CONFIG_VGA_ALLOCATE_EXTRA_STACK && GET_GLOBAL(ExtraStackSeg))
+ newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook_extrastack);
+ dprintf(1, "Hooking hardware timer irq (old=%x new=%x)\n"
+ , oldirq.segoff, newirq.segoff);
+ SET_VGA(Timer_Hook_Resume, oldirq);
+ SET_IVT(0x08, newirq);
+}
+
+
/****************************************************************
* VGA post
****************************************************************/
allocate_extra_stack();
+ hook_timer_irq();
+
SET_VGA(HaveRunInit, 1);
// Fixup checksum