diff --git a/kernel/main.v b/kernel/main.v index f4aba7700..0688c0506 100644 --- a/kernel/main.v +++ b/kernel/main.v @@ -32,6 +32,7 @@ import dev.serial import dev.streams import dev.ahci import dev.random +import dev.mouse import syscall.table import socket import time @@ -60,6 +61,7 @@ fn kmain_thread() { fbdev.register_driver(simple.get_driver()) console.initialise() serial.initialise() + mouse.initialise() $if !prod { ata.initialise() diff --git a/kernel/modules/dev/mouse/mouse.v b/kernel/modules/dev/mouse/mouse.v new file mode 100644 index 000000000..86a08feb9 --- /dev/null +++ b/kernel/modules/dev/mouse/mouse.v @@ -0,0 +1,220 @@ +module mouse + +import resource +import stat +import fs +import file +import event +import event.eventstruct +import klock +import katomic +import errno +import x86.kio +import x86.apic +import x86.idt + +@[inline] +fn wait(t int) { + mut timeout := 100000; + + if t == 0 { + for ; timeout != 0; timeout-- { + if kio.port_in(0x64) & (1 << 0) != 0 { + return + } + } + } else { + for ; timeout != 0; timeout-- { + if kio.port_in(0x64) & (1 << 1) == 0 { + return + } + } + } +} + +@[inline] +fn write(val u8) { + wait(1) + kio.port_out(0x64, 0xd4) + wait(1) + kio.port_out(0x60, val) +} + +@[inline] +fn read() u8 { + wait(0) + return kio.port_in(0x60) +} + +struct MousePacket { +pub mut: + flags u8 + x_mov u32 + y_mov u32 +} + +struct Mouse { +pub mut: + stat stat.Stat + refcount int + l klock.Lock + event eventstruct.Event + status int + can_mmap bool + + packet_avl bool + packet MousePacket +} + +fn (mut this Mouse) mmap(page u64, flags int) voidptr { + panic('') +} + +fn (mut this Mouse) read(_handle voidptr, buf voidptr, loc u64, count u64) ?i64 { + if count != sizeof(MousePacket) { + errno.set(errno.einval) + return none + } + + handle := unsafe { &file.Handle(_handle) } + + mouse_res.l.acquire() + + for mouse_res.packet_avl == false { + mouse_res.l.release() + + if handle.flags & resource.o_nonblock != 0 { + errno.set(errno.ewouldblock) + return none + } + + mut events := [&mouse_res.event] + event.await(mut events, true) or {} + + mouse_res.l.acquire() + } + + unsafe { + C.memcpy(buf, &mouse_res.packet, sizeof(MousePacket)) + } + mouse_res.packet_avl = false + + mouse_res.status &= ~int(file.pollin) + + mouse_res.l.release() + + return sizeof(MousePacket) +} + +fn (mut this Mouse) write(handle voidptr, buf voidptr, loc u64, count u64) ?i64 { + return i64(count) +} + +fn (mut this Mouse) ioctl(handle voidptr, request u64, argp voidptr) ?int { + return resource.default_ioctl(handle, request, argp) +} + +fn (mut this Mouse) unref(handle voidptr) ? { + katomic.dec(this.refcount) +} + +fn (mut this Mouse) link(handle voidptr) ? { + katomic.inc(this.stat.nlink) +} + +fn (mut this Mouse) unlink(handle voidptr) ? { + katomic.dec(this.stat.nlink) +} + +fn (mut this Mouse) grow(handle voidptr, new_size u64) ? { +} + +__global ( + mouse_res Mouse + ps2_mouse_vector u8 +) + +fn handler() { + mut handler_cycle := 0 + mut current_packet := MousePacket{} + mut discard_packet := false + + for { + mut events := [&int_events[ps2_mouse_vector]] + event.await(mut events, true) or {} + + // we will get some spurious packets at the beginning and they will screw + // up the alignment of the handler cycle so just ignore everything in + // the first 250 milliseconds after boot + if monotonic_clock.tv_sec == 0 && monotonic_clock.tv_nsec < 250000000 { + kio.port_in(0x60) + } + + match handler_cycle { + 0 { + current_packet.flags = read() + handler_cycle++ + if current_packet.flags & (1 << 6) != 0 || current_packet.flags & (1 << 7) != 0 { + discard_packet = true + } + if current_packet.flags & (1 << 3) == 0 { + discard_packet = true + } + continue + } + 1 { + current_packet.x_mov = read() + handler_cycle++ + continue + } + 2 { + current_packet.y_mov = read() + handler_cycle = 0 + + if discard_packet { + discard_packet = false + continue + } + } + else {} + } + + if current_packet.flags & (1 << 4) != 0 { + current_packet.x_mov = u32(i8(u8(current_packet.x_mov))) + } + if current_packet.flags & (1 << 5) != 0 { + current_packet.y_mov = u32(i8(u8(current_packet.y_mov))) + } + + mouse_res.l.acquire() + mouse_res.packet = current_packet + mouse_res.packet_avl = true + mouse_res.l.release() + + mouse_res.status |= file.pollin + event.trigger(mut mouse_res.event, false) + } +} + +pub fn initialise() { + write(0xf6) + read() + + write(0xf4) + read() + + mouse_res.stat.size = 0 + mouse_res.stat.blocks = 0 + mouse_res.stat.blksize = 512; + mouse_res.stat.rdev = resource.create_dev_id() + mouse_res.stat.mode = 0o644 | stat.ifchr + + mouse_res.status |= file.pollout + + fs.devtmpfs_add_device(&mouse_res, 'mouse') + + ps2_mouse_vector = idt.allocate_vector() + apic.io_apic_set_irq_redirect(cpu_locals[0].lapic_id, ps2_mouse_vector, 12, true) + + spawn handler() +}