aboutsummaryrefslogtreecommitdiff
path: root/kernel/drivers/ps2/mouse.c
blob: 1d3c1ae2cfc3691b0c332deb1c532b3a6abd6577 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// MIT License, Copyright (c) 2020 Marvin Borner

#include <boot.h>
#include <cpu.h>
#include <errno.h>
#include <interrupts.h>
#include <io.h>
#include <mem.h>
#include <print.h>
#include <proc.h>
#include <ps2.h>
#include <stack.h>
#include <str.h>
#include <sys.h>

PROTECTED static struct stack *queue = NULL;

static struct event_mouse *event = NULL;
static char mouse_cycle = 0;
static char mouse_byte[3] = { 0 };
static void mouse_handler(struct regs *r)
{
	UNUSED(r);
	switch (mouse_cycle) {
	case 0:
		mouse_byte[0] = ps2_read_data();
		if (((mouse_byte[0] >> 3) & 1) == 1)
			mouse_cycle++;
		else
			mouse_cycle = 0;
		break;
	case 1:
		mouse_byte[1] = ps2_read_data();
		mouse_cycle++;
		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;
		break;
	default:
		break;
	}
}

static res mouse_ready(void)
{
	return !stack_empty(queue);
}

static res 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 ps2_mouse_install(u8 device)
{
	u8 status;

	// 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();

	// Setup the mouse handler
	irq_install_handler(12, mouse_handler);

	queue = stack_new();
	struct io_dev *dev = zalloc(sizeof(*dev));
	dev->read = mouse_read;
	dev->ready = mouse_ready;
	io_add(IO_MOUSE, dev);
}