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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
// MIT License, Copyright (c) 2020 Marvin Borner
#include <assert.h>
#include <drivers/cpu.h>
#include <drivers/interrupts.h>
#include <drivers/ps2.h>
#include <errno.h>
#include <io.h>
#include <mem.h>
#include <print.h>
#include <proc.h>
#include <stack.h>
#include <str.h>
#include <sys.h>
PROTECTED static struct stack *queue = NULL;
PROTECTED static u8 wheel = 0;
PROTECTED static u8 extra_buttons = 0;
static char mouse_cycle = 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);
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();
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;
}
}
static res mouse_ready(void)
{
return !stack_empty(queue) ? EOK : -EAGAIN;
}
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 static u8 mouse_id(u8 device)
{
ps2_write_device(device, 0xf2);
return ps2_read_data();
}
CLEAR static void mouse_rate(u8 device, u8 rate)
{
ps2_write_device(device, 0xf3);
ps2_write_device(device, rate);
}
CLEAR void ps2_mouse_enable(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);
// 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;
}
mouse_rate(device, 20);
}
CLEAR void ps2_mouse_install(u8 device)
{
ps2_mouse_enable(device);
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);
}
|