aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2021-04-26 00:43:59 +0200
committerMarvin Borner2021-04-26 00:43:59 +0200
commit6b71accbaf4be52a1e2d3a696675c5e610a4c9b3 (patch)
tree4f2aa853d0bbcca23ad51c0a5d76278c536f83c9
parent0fe14a1ff936c38ab9aa7f85219d0c155d276823 (diff)
Added VMMouse support and improved PS/2 mouse
-rw-r--r--apps/wm/wm.c18
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/drivers/ps2/mouse.c90
-rw-r--r--kernel/drivers/ps2/ps2.c18
-rw-r--r--kernel/drivers/vmware.c167
-rw-r--r--kernel/features/io.c6
-rw-r--r--kernel/inc/ps2.h16
-rw-r--r--kernel/inc/vmware.h12
-rw-r--r--libs/libc/inc/sys.h14
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 {