diff options
Diffstat (limited to 'qemu/roms/seabios/src/mouse.c')
-rw-r--r-- | qemu/roms/seabios/src/mouse.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/qemu/roms/seabios/src/mouse.c b/qemu/roms/seabios/src/mouse.c new file mode 100644 index 000000000..6d1f5b77e --- /dev/null +++ b/qemu/roms/seabios/src/mouse.c @@ -0,0 +1,343 @@ +// 16bit code to handle mouse events. +// +// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2002 MandrakeSoft S.A. +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // GET_EBDA +#include "bregs.h" // struct bregs +#include "hw/ps2port.h" // ps2_mouse_command +#include "hw/usb-hid.h" // usb_mouse_command +#include "output.h" // dprintf +#include "stacks.h" // stack_hop_back +#include "util.h" // mouse_init + +void +mouse_init(void) +{ + if (! CONFIG_MOUSE) + return; + dprintf(3, "init mouse\n"); + // pointing device installed + set_equipment_flags(0x04, 0x04); +} + +static int +mouse_command(int command, u8 *param) +{ + if (usb_mouse_active()) + return usb_mouse_command(command, param); + return ps2_mouse_command(command, param); +} + +#define RET_SUCCESS 0x00 +#define RET_EINVFUNCTION 0x01 +#define RET_EINVINPUT 0x02 +#define RET_EINTERFACE 0x03 +#define RET_ENEEDRESEND 0x04 +#define RET_ENOHANDLER 0x05 + +// Disable Mouse +static void +mouse_15c20000(struct bregs *regs) +{ + int ret = mouse_command(PSMOUSE_CMD_DISABLE, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Enable Mouse +static void +mouse_15c20001(struct bregs *regs) +{ + u16 ebda_seg = get_ebda_seg(); + u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2); + if ((mouse_flags_2 & 0x80) == 0) { + set_code_invalid(regs, RET_ENOHANDLER); + return; + } + + int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +static void +mouse_15c200XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EINVFUNCTION); +} + +// Disable/Enable Mouse +static void +mouse_15c200(struct bregs *regs) +{ + switch (regs->bh) { + case 0x00: mouse_15c20000(regs); break; + case 0x01: mouse_15c20001(regs); break; + default: mouse_15c200XX(regs); break; + } +} + +// Reset Mouse +static void +mouse_15c201(struct bregs *regs) +{ + u8 param[2]; + int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param); + if (ret) { + set_code_invalid(regs, RET_ENEEDRESEND); + return; + } + regs->bl = param[0]; + regs->bh = param[1]; + set_code_success(regs); +} + +// Set Sample Rate +static void +mouse_15c202(struct bregs *regs) +{ + static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200}; + if (regs->bh >= ARRAY_SIZE(sample_rates)) { + set_code_invalid(regs, RET_EINVINPUT); + return; + } + u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]); + int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Set Resolution +static void +mouse_15c203(struct bregs *regs) +{ + // BH: + // 0 = 25 dpi, 1 count per millimeter + // 1 = 50 dpi, 2 counts per millimeter + // 2 = 100 dpi, 4 counts per millimeter + // 3 = 200 dpi, 8 counts per millimeter + if (regs->bh >= 4) { + set_code_invalid(regs, RET_EINVINPUT); + return; + } + u8 param = regs->bh; + int ret = mouse_command(PSMOUSE_CMD_SETRES, ¶m); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Get Device ID +static void +mouse_15c204(struct bregs *regs) +{ + u8 param[2]; + int ret = mouse_command(PSMOUSE_CMD_GETID, param); + if (ret) { + set_code_invalid(regs, RET_ENEEDRESEND); + return; + } + regs->bh = param[0]; + set_code_success(regs); +} + +// Initialize Mouse +static void +mouse_15c205(struct bregs *regs) +{ + if (regs->bh != 3) { + set_code_invalid(regs, RET_EINTERFACE); + return; + } + u16 ebda_seg = get_ebda_seg(); + SET_EBDA(ebda_seg, mouse_flag1, 0x00); + SET_EBDA(ebda_seg, mouse_flag2, regs->bh); + + // Reset Mouse + mouse_15c201(regs); +} + +// Return Status +static void +mouse_15c20600(struct bregs *regs) +{ + u8 param[3]; + int ret = mouse_command(PSMOUSE_CMD_GETINFO, param); + if (ret) { + set_code_invalid(regs, RET_ENEEDRESEND); + return; + } + regs->bl = param[0]; + regs->cl = param[1]; + regs->dl = param[2]; + set_code_success(regs); +} + +// Set Scaling Factor to 1:1 +static void +mouse_15c20601(struct bregs *regs) +{ + int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +// Set Scaling Factor to 2:1 +static void +mouse_15c20602(struct bregs *regs) +{ + int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL); + if (ret) + set_code_invalid(regs, RET_ENEEDRESEND); + else + set_code_success(regs); +} + +static void +mouse_15c206XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EINVFUNCTION); +} + +// Return Status & Set Scaling Factor... +static void +mouse_15c206(struct bregs *regs) +{ + switch (regs->bh) { + case 0x00: mouse_15c20600(regs); break; + case 0x01: mouse_15c20601(regs); break; + case 0x02: mouse_15c20602(regs); break; + default: mouse_15c206XX(regs); break; + } +} + +// Set Mouse Handler Address +static void +mouse_15c207(struct bregs *regs) +{ + struct segoff_s farptr = SEGOFF(regs->es, regs->bx); + u16 ebda_seg = get_ebda_seg(); + u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2); + if (! farptr.segoff) { + /* remove handler */ + if ((mouse_flags_2 & 0x80) != 0) { + mouse_flags_2 &= ~0x80; + mouse_command(PSMOUSE_CMD_DISABLE, NULL); + } + } else { + /* install handler */ + mouse_flags_2 |= 0x80; + } + SET_EBDA(ebda_seg, mouse_flag2, mouse_flags_2); + SET_EBDA(ebda_seg, far_call_pointer, farptr); + set_code_success(regs); +} + +static void +mouse_15c2XX(struct bregs *regs) +{ + set_code_unimplemented(regs, RET_EINVFUNCTION); +} + +void +handle_15c2(struct bregs *regs) +{ + //debug_stub(regs); + + if (! CONFIG_MOUSE) { + set_code_invalid(regs, RET_EUNSUPPORTED); + return; + } + + switch (regs->al) { + case 0x00: mouse_15c200(regs); break; + case 0x01: mouse_15c201(regs); break; + case 0x02: mouse_15c202(regs); break; + case 0x03: mouse_15c203(regs); break; + case 0x04: mouse_15c204(regs); break; + case 0x05: mouse_15c205(regs); break; + case 0x06: mouse_15c206(regs); break; + case 0x07: mouse_15c207(regs); break; + default: mouse_15c2XX(regs); break; + } +} + +void VISIBLE16 +invoke_mouse_handler(void) +{ + if (!CONFIG_MOUSE) + return; + if (need_hop_back()) { + extern void _cfunc16_invoke_mouse_handler(void); + stack_hop_back(0, 0, _cfunc16_invoke_mouse_handler); + return; + } + ASSERT16(); + u16 ebda_seg = get_ebda_seg(); + u16 status = GET_EBDA(ebda_seg, mouse_data[0]); + u16 X = GET_EBDA(ebda_seg, mouse_data[1]); + u16 Y = GET_EBDA(ebda_seg, mouse_data[2]); + + struct segoff_s func = GET_EBDA(ebda_seg, far_call_pointer); + dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n" + , status, X, Y, func.seg, func.offset); + + asm volatile( + "pushl %%ebp\n" + "sti\n" + + "pushl %0\n" + "pushw %w1\n" // status + "pushw %w2\n" // X + "pushw %w3\n" // Y + "pushw $0\n" // Z + "lcallw *8(%%esp)\n" + "addl $12, %%esp\n" + + "cli\n" + "cld\n" + "popl %%ebp" + : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y) + : + : "edi", "esi", "cc", "memory"); +} + +void +process_mouse(u8 data) +{ + if (!CONFIG_MOUSE) + return; + + u16 ebda_seg = get_ebda_seg(); + u8 mouse_flags_1 = GET_EBDA(ebda_seg, mouse_flag1); + u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2); + + if (! (mouse_flags_2 & 0x80)) + // far call handler not installed + return; + + u8 package_count = mouse_flags_2 & 0x07; + u8 index = mouse_flags_1 & 0x07; + SET_EBDA(ebda_seg, mouse_data[index], data); + + if ((index+1) < package_count) { + mouse_flags_1++; + SET_EBDA(ebda_seg, mouse_flag1, mouse_flags_1); + return; + } + + SET_EBDA(ebda_seg, mouse_flag1, 0); + invoke_mouse_handler(); +} |