diff options
author | Marvin Borner | 2021-04-26 00:43:59 +0200 |
---|---|---|
committer | Marvin Borner | 2021-04-26 00:43:59 +0200 |
commit | 6b71accbaf4be52a1e2d3a696675c5e610a4c9b3 (patch) | |
tree | 4f2aa853d0bbcca23ad51c0a5d76278c536f83c9 | |
parent | 0fe14a1ff936c38ab9aa7f85219d0c155d276823 (diff) |
Added VMMouse support and improved PS/2 mouse
-rw-r--r-- | apps/wm/wm.c | 18 | ||||
-rw-r--r-- | kernel/Makefile | 1 | ||||
-rw-r--r-- | kernel/drivers/ps2/mouse.c | 90 | ||||
-rw-r--r-- | kernel/drivers/ps2/ps2.c | 18 | ||||
-rw-r--r-- | kernel/drivers/vmware.c | 167 | ||||
-rw-r--r-- | kernel/features/io.c | 6 | ||||
-rw-r--r-- | kernel/inc/ps2.h | 16 | ||||
-rw-r--r-- | kernel/inc/vmware.h | 12 | ||||
-rw-r--r-- | libs/libc/inc/sys.h | 14 |
9 files changed, 290 insertions, 52 deletions
diff --git a/apps/wm/wm.c b/apps/wm/wm.c index 7b88764..8860cdc 100644 --- a/apps/wm/wm.c +++ b/apps/wm/wm.c @@ -293,6 +293,7 @@ static void window_redraw(struct window *win) vec2 pos2 = vec2(pos1.x + win->ctx.size.x, pos1.y + win->ctx.size.y); rectangle_redraw(pos1, pos2); + gfx_ctx_on_ctx(&direct->ctx, &win->ctx, win->pos); } // TODO: Fix strange artifacts after destroying @@ -347,8 +348,14 @@ static void handle_event_mouse(struct event_mouse *event) cursor->pos_prev = mouse.pos; - mouse.pos.x += event->diff_x; - mouse.pos.y -= event->diff_y; + if (event->rel) { + mouse.pos.x += (s32)event->pos.x; + mouse.pos.y -= (s32)event->pos.y; + } else { + // TODO: Support other absolute scaling than 0xffff (VMWare default) + mouse.pos.x = event->pos.x * screen.width / 0xffff; + mouse.pos.y = event->pos.y * screen.height / 0xffff; + } // Fix x overflow if ((signed)mouse.pos.x < 0) @@ -365,10 +372,11 @@ static void handle_event_mouse(struct event_mouse *event) cursor->pos = mouse.pos; struct window *win = window_at(mouse.pos); - if (win && !(win->flags & WF_NO_FOCUS) && !event->but1 && !event->but2 && !event->but3) + if (win && !(win->flags & WF_NO_FOCUS) && !event->but.left && !event->but.right && + !event->but.middle) focused = win; - if (focused && !(focused->flags & WF_NO_DRAG) && event->but1 && special_keys.alt) { + if (focused && !(focused->flags & WF_NO_DRAG) && event->but.left && special_keys.alt) { focused->pos_prev = focused->pos; focused->pos = mouse.pos; window_redraw(focused); @@ -384,7 +392,7 @@ static void handle_event_mouse(struct event_mouse *event) msg.header.state = MSG_GO_ON; msg.id = win->id; msg.pos = vec2_sub(mouse.pos, win->pos); - msg.bits.click = event->but1; + msg.bits.click = event->but.left; if (msg_connect_conn(win->client.conn) == EOK) msg_send(GUI_MOUSE, &msg, sizeof(msg)); diff --git a/kernel/Makefile b/kernel/Makefile index 17a89b7..60b4ee7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,6 +10,7 @@ COBJS = main.o \ drivers/ide.o \ drivers/fb.o \ drivers/timer.o \ + drivers/vmware.o \ drivers/ps2/ps2.o \ drivers/ps2/mouse.o \ drivers/ps2/keyboard.o \ diff --git a/kernel/drivers/ps2/mouse.c b/kernel/drivers/ps2/mouse.c index ba6d338..7154eef 100644 --- a/kernel/drivers/ps2/mouse.c +++ b/kernel/drivers/ps2/mouse.c @@ -1,5 +1,6 @@ // MIT License, Copyright (c) 2020 Marvin Borner +#include <assert.h> #include <boot.h> #include <cpu.h> #include <errno.h> @@ -15,9 +16,27 @@ PROTECTED static struct stack *queue = NULL; -static struct event_mouse *event = NULL; +PROTECTED static u8 wheel = 0; +PROTECTED static u8 extra_buttons = 0; + static char mouse_cycle = 0; -static char mouse_byte[3] = { 0 }; +static char mouse_byte[4] = { 0 }; +static void mouse_finish(void) +{ + struct event_mouse *event = zalloc(sizeof(*event)); + event->magic = MOUSE_MAGIC; + event->pos = vec2(mouse_byte[1], mouse_byte[2]); + event->rel = 1; + event->scroll = mouse_byte[3] & 0x0f; + event->scroll = event->scroll == 0x0f ? -1 : event->scroll; // Weird nibble stuff + event->but.left = mouse_byte[0] & 1; + event->but.right = (mouse_byte[0] >> 1) & 1; + event->but.middle = (mouse_byte[0] >> 2) & 1; + stack_push_bot(queue, event); + mouse_cycle = 0; + io_unblock(IO_MOUSE); +} + static void mouse_handler(struct regs *r) { UNUSED(r); @@ -35,19 +54,18 @@ static void mouse_handler(struct regs *r) break; case 2: mouse_byte[2] = ps2_read_data(); - - event = malloc(sizeof(*event)); - event->magic = MOUSE_MAGIC; - event->diff_x = mouse_byte[1]; - event->diff_y = mouse_byte[2]; - event->but1 = mouse_byte[0] & 1; - event->but2 = (mouse_byte[0] >> 1) & 1; - event->but3 = (mouse_byte[0] >> 2) & 1; - stack_push_bot(queue, event); - mouse_cycle = 0; - io_unblock(IO_MOUSE); + if (wheel) { + mouse_cycle++; + break; + } + mouse_finish(); + break; + case 3: + mouse_byte[3] = ps2_read_data(); + mouse_finish(); break; default: + panic("Unknown mouse state\n"); break; } } @@ -68,26 +86,52 @@ static res mouse_read(void *buf, u32 offset, u32 count) return MIN(count, sizeof(*e)); } -CLEAR void ps2_mouse_install(u8 device) +CLEAR static u8 mouse_id(u8 device) +{ + ps2_write_device(device, 0xf2); + return ps2_read_data(); +} + +CLEAR static void mouse_rate(u8 device, u8 rate) { - u8 status; + ps2_write_device(device, 0xf3); + ps2_write_device(device, rate); +} +CLEAR void ps2_mouse_install(u8 device) +{ // Enable auxiliary mouse device ps2_write_device(device, 0xa8); - // Enable interrupts - ps2_write_command(0x20); - status = ps2_read_data() | 3; - ps2_write_command(0x60); - ps2_write_data(status); - // Use default settings ps2_write_device(device, 0xf6); - ps2_read_data(); // Enable mouse ps2_write_device(device, 0xf4); - ps2_read_data(); + + // Verify ID + u8 id = mouse_id(device); + assert(PS2_MOUSE(id)); + + // Enable wheel + if (id != PS2_TYPE_WHEEL_MOUSE) { + mouse_rate(device, 200); + mouse_rate(device, 100); + mouse_rate(device, 80); + id = mouse_id(device); + if (id == PS2_TYPE_WHEEL_MOUSE) + wheel = 1; + } + + // Enable extra buttons + if (id == PS2_TYPE_WHEEL_MOUSE) { + mouse_rate(device, 200); + mouse_rate(device, 200); + mouse_rate(device, 80); + id = mouse_id(device); + if (id == PS2_TYPE_BUTTON_MOUSE) + extra_buttons = 1; + } // Setup the mouse handler irq_install_handler(12, mouse_handler); diff --git a/kernel/drivers/ps2/ps2.c b/kernel/drivers/ps2/ps2.c index 7045fbe..bc93b03 100644 --- a/kernel/drivers/ps2/ps2.c +++ b/kernel/drivers/ps2/ps2.c @@ -8,7 +8,7 @@ #define PS2_TIMEOUT 100000 -struct ps2_status ps2_read_status(void) +static struct ps2_status ps2_read_status(void) { u8 byte = inb(0x64); return *(struct ps2_status *)&byte; @@ -53,7 +53,7 @@ u8 ps2_write_data(u8 byte) } } -u8 ps2_write_command(u8 byte) +CLEAR static u8 ps2_write_command(u8 byte) { if (ps2_wait_writable()) { outb(0x64, byte); @@ -79,20 +79,6 @@ CLEAR static u8 ps2_write_config(struct ps2_config config) return ps2_write_data(*(u8 *)&config); } -#define PS2_TYPE_STANDARD_MOUSE 0x0000 -#define PS2_TYPE_WHEEL_MOUSE 0x0003 -#define PS2_TYPE_BUTTON_MOUSE 0x0004 -#define PS2_TYPE_TRANSLATION_KEYBOARD1 0xab41 -#define PS2_TYPE_TRANSLATION_KEYBOARD2 0xabc1 -#define PS2_TYPE_STANDARD_KEYBOARD 0xab83 - -#define PS2_KEYBOARD(type) \ - ((type) == PS2_TYPE_TRANSLATION_KEYBOARD1 || (type) == PS2_TYPE_TRANSLATION_KEYBOARD2 || \ - (type) == PS2_TYPE_STANDARD_KEYBOARD) -#define PS2_MOUSE(type) \ - ((type) == PS2_TYPE_STANDARD_MOUSE || (type) == PS2_TYPE_WHEEL_MOUSE || \ - (type) == PS2_TYPE_BUTTON_MOUSE) - PROTECTED static struct { u8 detected : 1; struct { diff --git a/kernel/drivers/vmware.c b/kernel/drivers/vmware.c new file mode 100644 index 0000000..795eb79 --- /dev/null +++ b/kernel/drivers/vmware.c @@ -0,0 +1,167 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// VMWare extensions/backdoors for better VM integration + +#include <def.h> +#include <interrupts.h> +#include <io.h> +#include <mem.h> +#include <print.h> +#include <ps2.h> +#include <stack.h> +#include <vmware.h> + +#define VMWARE_CMD_VERSION 0x0a + +#define VMWARE_MAGIC 0x564d5868 +#define VMWARE_PORT 0x5658 + +struct vmware_command { + union { + u32 ax; + u32 magic; + } a; + union { + u32 bx; + u16 size; + } b; + union { + u32 cx; + u16 command; + } c; + union { + u32 dx; + u16 port; + } d; + u32 si; + u32 di; +}; + +static void vmware_out(struct vmware_command *command) +{ + command->a.magic = VMWARE_MAGIC; + command->d.port = VMWARE_PORT; + command->si = 0; + command->di = 0; + __asm__ volatile("in %%dx, %0" + : "+a"(command->a.ax), "+b"(command->b.bx), "+c"(command->c.cx), + "+d"(command->d.dx), "+S"(command->si), "+D"(command->di)); +} + +CLEAR u8 vmware_detect(void) +{ + struct vmware_command command = { .b.bx = ~VMWARE_MAGIC, .c.command = VMWARE_CMD_VERSION }; + vmware_out(&command); + return command.b.bx == VMWARE_MAGIC && command.a.ax != U32_MAX; +} + +/** + * VMWare mouse + */ + +#define VMMOUSE_DATA 39 +#define VMMOUSE_STATUS 40 +#define VMMOUSE_COMMAND 41 + +#define VMMOUSE_QEMU 0x3442554a +#define VMMOUSE_READ 0x45414552 +#define VMMOUSE_RELATIVE 0x4c455252 +#define VMMOUSE_ABSOLUTE 0x53424152 +#define VMMOUSE_LEFT_CLICK 0x20 +#define VMMOUSE_RIGHT_CLICK 0x10 +#define VMMOUSE_MIDDLE_CLICK 0x08 + +PROTECTED static struct stack *queue = NULL; + +CLEAR u8 vmware_mouse_detect(void) +{ + struct vmware_command command = { .b.bx = VMMOUSE_READ, .c.command = VMMOUSE_COMMAND }; + vmware_out(&command); + command.b.bx = 1; + command.c.command = VMMOUSE_DATA; + vmware_out(&command); + return command.a.ax == VMMOUSE_QEMU; +} + +CLEAR static void vmware_mouse_enable(void) +{ + struct vmware_command command = { .b.bx = 0, .c.command = VMMOUSE_STATUS }; + vmware_out(&command); + if (command.a.ax == (0xffffu << 16)) + return; + + command.b.bx = VMMOUSE_ABSOLUTE; + command.c.command = VMMOUSE_COMMAND; + vmware_out(&command); +} + +static void vmware_mouse_handler(struct regs *r) +{ + UNUSED(r); + ps2_read_data(); // Unused, for PS/2 compatibility + + struct vmware_command command = { .b.bx = 0, .c.command = VMMOUSE_STATUS }; + vmware_out(&command); + if (command.a.ax == (0xffffu << 16)) + return; + + u32 cnt = command.a.ax & 0xffff; + if (!cnt || cnt % 4) + return; + + command.b.size = 4; + command.c.command = VMMOUSE_DATA; + vmware_out(&command); + + u32 buttons = command.a.ax & 0xffff; + s8 scroll = command.d.dx & 0xff; + s32 x = command.b.bx; + s32 y = command.c.cx; + + struct event_mouse *event = zalloc(sizeof(*event)); + event->magic = MOUSE_MAGIC; + event->pos = vec2(x, y); + event->rel = 0; + event->scroll = scroll; + event->but.left = (buttons & VMMOUSE_LEFT_CLICK) != 0; + event->but.right = (buttons & VMMOUSE_RIGHT_CLICK) != 0; + event->but.middle = (buttons & VMMOUSE_MIDDLE_CLICK) != 0; + stack_push_bot(queue, event); + io_unblock(IO_MOUSE); +} + +static res vmware_mouse_ready(void) +{ + return !stack_empty(queue) ? EOK : -EAGAIN; +} + +static res vmware_mouse_read(void *buf, u32 offset, u32 count) +{ + if (stack_empty(queue)) + return -EINVAL; + + struct event_mouse *e = stack_pop(queue); + memcpy_user(buf, (u8 *)e + offset, MIN(count, sizeof(*e))); + free(e); + return MIN(count, sizeof(*e)); +} + +CLEAR void vmware_mouse_install(u8 device) +{ + // Enable auxiliary mouse device + ps2_write_device(device, 0xa8); + + // Use default settings + ps2_write_device(device, 0xf6); + + // Enable mouse + ps2_write_device(device, 0xf4); + + vmware_mouse_enable(); + irq_install_handler(12, vmware_mouse_handler); + + queue = stack_new(); + struct io_dev *dev = zalloc(sizeof(*dev)); + dev->read = vmware_mouse_read; + dev->ready = vmware_mouse_ready; + io_add(IO_MOUSE, dev); +} diff --git a/kernel/features/io.c b/kernel/features/io.c index d4737bf..da179ab 100644 --- a/kernel/features/io.c +++ b/kernel/features/io.c @@ -17,6 +17,7 @@ #include <str.h> #include <syscall.h> #include <timer.h> +#include <vmware.h> struct io_listener { u32 group; @@ -215,7 +216,10 @@ CLEAR void io_install(struct boot_info *boot) u8 ps2_mouse = ps2_mouse_detect(); if (ps2_mouse != U8_MAX) { - ps2_mouse_install(ps2_mouse); + if (vmware_detect() && vmware_mouse_detect()) + vmware_mouse_install(ps2_mouse); + else + ps2_mouse_install(ps2_mouse); } timer_install(); diff --git a/kernel/inc/ps2.h b/kernel/inc/ps2.h index 42d8127..b81d1f8 100644 --- a/kernel/inc/ps2.h +++ b/kernel/inc/ps2.h @@ -8,6 +8,20 @@ #define PS2_ACK 0xfa #define PS2_RESEND 0xfe +#define PS2_TYPE_STANDARD_MOUSE 0x0000 +#define PS2_TYPE_WHEEL_MOUSE 0x0003 +#define PS2_TYPE_BUTTON_MOUSE 0x0004 +#define PS2_TYPE_TRANSLATION_KEYBOARD1 0xab41 +#define PS2_TYPE_TRANSLATION_KEYBOARD2 0xabc1 +#define PS2_TYPE_STANDARD_KEYBOARD 0xab83 + +#define PS2_KEYBOARD(type) \ + ((type) == PS2_TYPE_TRANSLATION_KEYBOARD1 || (type) == PS2_TYPE_TRANSLATION_KEYBOARD2 || \ + (type) == PS2_TYPE_STANDARD_KEYBOARD) +#define PS2_MOUSE(type) \ + ((type) == PS2_TYPE_STANDARD_MOUSE || (type) == PS2_TYPE_WHEEL_MOUSE || \ + (type) == PS2_TYPE_BUTTON_MOUSE) + struct ps2_status { u8 in_full : 1; u8 out_full : 1; @@ -31,8 +45,6 @@ struct ps2_config { u8 ps2_read_data(void); u8 ps2_write_data(u8 byte); -struct ps2_status ps2_read_status(void); -u8 ps2_write_command(u8 byte); u8 ps2_write_device(u8 device, u8 data); void ps2_detect(void); diff --git a/kernel/inc/vmware.h b/kernel/inc/vmware.h new file mode 100644 index 0000000..243c624 --- /dev/null +++ b/kernel/inc/vmware.h @@ -0,0 +1,12 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef VMWARE_H +#define VMWARE_H + +#include <def.h> + +u8 vmware_detect(void); +u8 vmware_mouse_detect(void); +void vmware_mouse_install(u8 device); + +#endif diff --git a/libs/libc/inc/sys.h b/libs/libc/inc/sys.h index 8c8e217..f65e020 100644 --- a/libs/libc/inc/sys.h +++ b/libs/libc/inc/sys.h @@ -6,6 +6,7 @@ #include <def.h> #include <errno.h> +#include <vec.h> #define KEYBOARD_MAGIC 0x555555 #define MOUSE_MAGIC 0xaaaaaa @@ -64,11 +65,14 @@ struct event_keyboard { struct event_mouse { u32 magic; - s32 diff_x; - s32 diff_y; - u8 but1; - u8 but2; - u8 but3; + vec2 pos; + u8 rel; // 1 rel, 0 abs + s8 scroll; // Dir: -1 neg, +1 pos + struct { + u8 left : 1; + u8 right : 1; + u8 middle : 1; + } but; }; struct stat { |