Change the timer syscalls so that sysret_t can be 32-bit
[monolithium.git] / drivers / ps2 / src / main.c
1 /*
2  * PS/2 (Keyboard and Mouse) Driver
3  * main.c
4  *
5  * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "ps2.h"
22 #include <irq.h>
23 #include <device.h>
24 #include <timer.h>
25 #include <heap.h>
26 #include <stdio.h>
27 #include <semaphore.h>
28
29 const char driver_name[] = "ps2";
30
31 static dword_t ps2_init(void);
32 static dword_t ps2_cleanup(void);
33 static dword_t ps2_read(device_t *device, void *buffer, size_t length, size_t *bytes_read);
34 static dword_t ps2_write(device_t *device, const void *buffer, size_t length, size_t *bytes_written);
35 static dword_t ps2_ioctl(device_t *device, dword_t control_code, const void *in_buffer, size_t in_length, void *out_buffer, size_t out_length);
36
37 static char_dev_driver_t ps2_driver_block = {
38     .init_proc = ps2_init,
39     .cleanup_proc = ps2_cleanup,
40     .read_proc = ps2_read,
41     .write_proc = ps2_write,
42     .ioctl_proc = ps2_ioctl
43 };
44
45 static semaphore_t irq_mutex[2];
46 static ps2_device_t *ps2_devices[2] = { NULL };
47
48 static inline bool_t poll_and_read(byte_t *byte)
49 {
50     qword_t end_time = timer_get_milliseconds() + (qword_t)PS2_TIMEOUT;
51
52     while (!(cpu_read_port_byte(PS2_STATUS_PORT) & PS2_OUTPUT_BUFFER_FULL))
53     {
54         if (timer_get_milliseconds() >= end_time) return FALSE;
55     }
56
57     *byte = cpu_read_port_byte(PS2_DATA_PORT);
58     return TRUE;
59 }
60
61 static inline bool_t poll_and_write(byte_t byte)
62 {
63     qword_t end_time = timer_get_milliseconds() + (qword_t)PS2_TIMEOUT;
64
65     while (cpu_read_port_byte(PS2_STATUS_PORT) & PS2_INPUT_BUFFER_FULL)
66     {
67         if (timer_get_milliseconds() >= end_time) return FALSE;
68     }
69
70     cpu_write_port_byte(PS2_DATA_PORT, byte);
71     return TRUE;
72 }
73
74 static inline byte_t ps2_send_command(byte_t port, byte_t command, int num_params, ...)
75 {
76     int i;
77     int retries = PS2_MAX_RETRIES;
78     byte_t response;
79     va_list args;
80
81     while (retries--)
82     {
83         cpu_read_port_byte(PS2_DATA_PORT);
84
85         if (port) cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_SEND_TO_SECONDARY);
86         if (!poll_and_write(command)) return PS2_DEVICE_RESPONSE_FAILURE;
87
88         va_start(args, num_params);
89
90         for (i = 0; i < num_params; i++)
91         {
92             if (port) cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_SEND_TO_SECONDARY);
93             if (!poll_and_write(va_arg(args, uintptr_t)))
94             {
95                 va_end(args);
96                 return PS2_DEVICE_RESPONSE_FAILURE;
97             }
98         }
99
100         va_end(args);
101
102         if (!poll_and_read(&response)) return PS2_DEVICE_RESPONSE_FAILURE;
103         if (response != PS2_DEVICE_RESPONSE_RESEND) break;
104     }
105
106     return response;
107 }
108
109 static void ps2_irq_handler(registers_t *registers, byte_t int_num)
110 {
111     byte_t port = int_num == PS2_FIRST_IRQ ? 0 : 1;
112     release_mutex(&irq_mutex[port]);
113
114     if (!(cpu_read_port_byte(PS2_STATUS_PORT) & PS2_OUTPUT_BUFFER_FULL)) return;
115     byte_t buffer = cpu_read_port_byte(PS2_DATA_PORT);
116
117     if (buffer == 0xAA && ps2_devices[port] == NULL)
118     {
119         ps2_device_type_t type;
120
121         if (ps2_send_command(port, PS2_DEVICE_CMD_DISABLE_SCAN, 0) != PS2_DEVICE_RESPONSE_ACK) return;
122         if (ps2_send_command(port, PS2_DEVICE_CMD_IDENTIFY, 0) != PS2_DEVICE_RESPONSE_ACK) return;
123
124         if (poll_and_read(&buffer))
125         {
126             byte_t second_byte;
127
128             if (poll_and_read(&second_byte))
129             {
130                 if (port == 0) type = PS2_DEVICE_KEYBOARD;
131                 else type = PS2_DEVICE_KEYBOARD;
132             }
133             else
134             {
135                 if (port == 0) type = PS2_DEVICE_MOUSE;
136                 else type = PS2_DEVICE_MOUSE;
137             }
138         }
139         else
140         {
141             type = PS2_DEVICE_KEYBOARD;
142         }
143
144         if (type == PS2_DEVICE_KEYBOARD)
145         {
146             if (ps2_send_command(port, PS2_DEVICE_CMD_SCANCODE_SET, 1, 1) != PS2_DEVICE_RESPONSE_ACK) return;
147         }
148
149         if (ps2_send_command(port, PS2_DEVICE_CMD_ENABLE_SCAN, 0) != PS2_DEVICE_RESPONSE_ACK) return;
150
151         if (type == PS2_DEVICE_KEYBOARD)
152         {
153             ps2_keyboard_t *keyboard = (ps2_keyboard_t*)malloc(sizeof(ps2_keyboard_t));
154             if (keyboard == NULL) return;
155
156             sprintf(keyboard->header.header.name, "PS2Keyboard%d", port);
157             keyboard->header.header.driver= &ps2_driver_block;
158
159             keyboard->header.port = port;
160             keyboard->header.type = PS2_DEVICE_KEYBOARD;
161             lock_init(&keyboard->header.buffer_lock);
162             keyboard->header.buffer_start = keyboard->header.buffer_end = 0;
163
164             if (register_char_device(&keyboard->header.header) == ERR_SUCCESS) ps2_devices[port] = &keyboard->header;
165             else free(keyboard);
166         }
167         else if (type == PS2_DEVICE_MOUSE)
168         {
169             ps2_mouse_t *mouse = (ps2_mouse_t*)malloc(sizeof(ps2_mouse_t));
170             if (mouse == NULL) return;
171
172             sprintf(mouse->header.header.name, "PS2Mouse%d", port);
173             mouse->header.header.driver= &ps2_driver_block;
174
175             mouse->header.port = port;
176             mouse->header.type = PS2_DEVICE_MOUSE;
177             lock_init(&mouse->header.buffer_lock);
178
179             if (register_char_device(&mouse->header.header) == ERR_SUCCESS) ps2_devices[port] = &mouse->header;
180             else free(mouse);
181         }
182     }
183     else if (ps2_devices[port])
184     {
185         lock_acquire(&ps2_devices[port]->buffer_lock);
186
187         if (ps2_devices[port]->type == PS2_DEVICE_KEYBOARD)
188         {
189             ps2_keyboard_t *keyboard = CONTAINER_OF(ps2_devices[port], ps2_keyboard_t, header);
190
191             if (((ps2_devices[port]->buffer_end + 1) % PS2_BUFFER_CAPACITY) != ps2_devices[port]->buffer_start)
192             {
193                 keyboard->buffer[ps2_devices[port]->buffer_end] = buffer;
194
195                 ps2_devices[port]->buffer_end++;
196                 ps2_devices[port]->buffer_end %= PS2_BUFFER_CAPACITY;
197             }
198         }
199         else if (ps2_devices[port]->type == PS2_DEVICE_MOUSE)
200         {
201             ps2_mouse_t *mouse = CONTAINER_OF(ps2_devices[port], ps2_mouse_t, header);
202
203             mouse->unfinished_packet[mouse->phase++] = buffer;
204
205             if (mouse->phase == 3)
206             {
207                 if (((ps2_devices[port]->buffer_end + 1) % PS2_BUFFER_CAPACITY) != ps2_devices[port]->buffer_start)
208                 {
209                     ps2_mouse_packet_t packet;
210
211                     packet.flags = mouse->unfinished_packet[0] & 0x07;
212
213                     packet.delta_x = (int32_t)((dword_t)mouse->unfinished_packet[1]);
214                     if ((mouse->unfinished_packet[0] >> 4) & 1) packet.delta_x = -packet.delta_x;
215
216                     packet.delta_y = (int32_t)((dword_t)mouse->unfinished_packet[2]);
217                     if ((mouse->unfinished_packet[0] >> 5) & 1) packet.delta_y = -packet.delta_y;
218
219                     mouse->buffer[ps2_devices[port]->buffer_end] = packet;
220
221                     ps2_devices[port]->buffer_end++;
222                     ps2_devices[port]->buffer_end %= PS2_BUFFER_CAPACITY;
223                 }
224
225                 mouse->phase = 0;
226             }
227         }
228
229         lock_release(&ps2_devices[port]->buffer_lock);
230     }
231 }
232
233 static dword_t ps2_init(void)
234 {
235     init_mutex(&irq_mutex[0], 0);
236     init_mutex(&irq_mutex[1], 0);
237
238     byte_t working_ports = 3;
239     byte_t buffer;
240
241     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_DISABLE_FIRST_PORT);
242     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_DISABLE_SECOND_PORT);
243
244     while (cpu_read_port_byte(PS2_STATUS_PORT) & PS2_OUTPUT_BUFFER_FULL) cpu_read_port_byte(PS2_DATA_PORT);
245
246     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_TEST_CONTROLLER);
247     if (!poll_and_read(&buffer)) return ERR_HARDWARE;
248     if (buffer != 0x55) return ERR_HARDWARE;
249
250     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_READ_CONFIG);
251     byte_t config;
252     if (!poll_and_read(&config)) return ERR_HARDWARE;
253
254     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_WRITE_CONFIG);
255     if (!poll_and_write(1 << 2)) return ERR_HARDWARE;
256
257     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_TEST_FIRST_PORT);
258     if (!poll_and_read(&buffer)) working_ports &= ~(1 << 0);
259     if (buffer) working_ports &= ~(1 << 0);
260
261     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_TEST_SECOND_PORT);
262     if (!poll_and_read(&buffer)) working_ports &= ~(1 << 1);
263     if (buffer) working_ports &= ~(1 << 1);
264     if (!working_ports) return ERR_NOTFOUND;
265
266     if (working_ports & (1 << 0))
267     {
268         if (register_irq_handler(PS2_FIRST_IRQ, &ps2_irq_handler, FALSE) != ERR_SUCCESS)
269         {
270             working_ports &= ~(1 << 0);
271         }
272     }
273
274     if (working_ports & (1 << 1))
275     {
276         if (register_irq_handler(PS2_SECOND_IRQ, &ps2_irq_handler, FALSE) != ERR_SUCCESS)
277         {
278             working_ports &= ~(1 << 1);
279         }
280     }
281
282     config |= working_ports;
283     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_WRITE_CONFIG);
284     if (!poll_and_write(config)) return ERR_HARDWARE;
285
286     if (working_ports & (1 << 0)) cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_ENABLE_FIRST_PORT);
287     if (working_ports & (1 << 1)) cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_ENABLE_SECOND_PORT);
288
289     if (working_ports & (1 << 0)) poll_and_write(PS2_DEVICE_CMD_RESET);
290
291     if (working_ports & (1 << 1))
292     {
293         cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_SEND_TO_SECONDARY);
294         poll_and_write(PS2_DEVICE_CMD_RESET);
295     }
296
297     return ERR_SUCCESS;
298 }
299
300 static dword_t ps2_cleanup(void)
301 {
302     int i;
303
304     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_DISABLE_FIRST_PORT);
305     cpu_write_port_byte(PS2_CONTROL_PORT, PS2_CMD_DISABLE_SECOND_PORT);
306
307     unregister_irq_handler(PS2_FIRST_IRQ, &ps2_irq_handler);
308     unregister_irq_handler(PS2_SECOND_IRQ, &ps2_irq_handler);
309
310     for (i = 0; i < 2; i++)
311     {
312         unregister_char_device(&ps2_devices[i]->header);
313         free(ps2_devices[i]);
314     }
315
316     return ERR_SUCCESS;
317 }
318
319 static dword_t ps2_read(device_t *device, void *buffer, size_t length, size_t *bytes_read)
320 {
321     ps2_device_t *ps2_device = CONTAINER_OF(device, ps2_device_t, header);
322
323     if (ps2_device->type == PS2_DEVICE_KEYBOARD)
324     {
325         ps2_keyboard_t *keyboard = CONTAINER_OF(ps2_device, ps2_keyboard_t, header);
326         byte_t *byte_buffer = (byte_t*)buffer;
327
328         while (length > 0)
329         {
330             lock_acquire(&ps2_device->buffer_lock);
331
332             while (ps2_device->buffer_start != ps2_device->buffer_end)
333             {
334                 *byte_buffer++ = keyboard->buffer[ps2_device->buffer_start];
335                 ps2_device->buffer_start++;
336                 ps2_device->buffer_start %= PS2_BUFFER_CAPACITY;
337                 if (--length == 0) break;
338             }
339
340             lock_release(&ps2_device->buffer_lock);
341             if (length > 0) wait_mutex(&irq_mutex[ps2_device->port], NO_TIMEOUT);
342         }
343
344         return ERR_SUCCESS;
345     }
346     else if (ps2_device->type == PS2_DEVICE_MOUSE)
347     {
348         ps2_mouse_t *mouse = CONTAINER_OF(ps2_device, ps2_mouse_t, header);
349         ps2_mouse_packet_t *packet_buffer = (ps2_mouse_packet_t*)buffer;
350         length /= sizeof(ps2_mouse_packet_t);
351
352         while (length > 0)
353         {
354             lock_acquire(&ps2_device->buffer_lock);
355
356             while (ps2_device->buffer_start != ps2_device->buffer_end)
357             {
358                 *packet_buffer++ = mouse->buffer[ps2_device->buffer_start];
359                 ps2_device->buffer_start++;
360                 ps2_device->buffer_start %= PS2_BUFFER_CAPACITY;
361                 if (--length == 0) break;
362             }
363
364             lock_release(&ps2_device->buffer_lock);
365             if (length > 0) wait_mutex(&irq_mutex[ps2_device->port], NO_TIMEOUT);
366         }
367
368         return ERR_SUCCESS;
369     }
370     else
371     {
372         return ERR_INVALID;
373     }
374 }
375
376 static dword_t ps2_write(device_t *device, const void *buffer, size_t length, size_t *bytes_written)
377 {
378     return ERR_INVALID;
379 }
380
381 static dword_t ps2_ioctl(device_t *device, dword_t control_code, const void *in_buffer, size_t in_length, void *out_buffer, size_t out_length)
382 {
383     ps2_device_t *ps2_device = CONTAINER_OF(device, ps2_device_t, header);
384
385     switch (control_code)
386     {
387     case IOCTL_CHAR_DEV_CHECK_INPUT:
388         if (out_length >= sizeof(size_t))
389         {
390             lock_acquire(&ps2_device->buffer_lock);
391
392             if (ps2_device->buffer_start <= ps2_device->buffer_end)
393             {
394                 *((size_t*)out_buffer) = ps2_device->buffer_end - ps2_device->buffer_start;
395             }
396             else
397             {
398                 *((size_t*)out_buffer) = ps2_device->buffer_end + PS2_BUFFER_CAPACITY - ps2_device->buffer_start;
399             }
400
401             lock_release(&ps2_device->buffer_lock);
402             return ERR_SUCCESS;
403         }
404         else
405         {
406             return ERR_SMALLBUF;
407         }
408
409     default:
410         return ERR_INVALID;
411     }
412 }
413
414 dword_t driver_load(const char *parameters)
415 {
416     return register_char_dev_driver(&ps2_driver_block);
417 }