From 9a43ead118ec1506848bad9d2bcddfb0fd458552 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Sun, 7 Aug 2022 22:07:27 +0200 Subject: kernel: ps2 mouse support --- src/kernel/arch/amd64/driver/ps2.c | 111 ++++++++++++++++++++++++++------- src/kernel/arch/amd64/driver/serial.c | 2 +- src/kernel/arch/amd64/interrupts/irq.c | 10 +-- src/kernel/arch/amd64/interrupts/irq.h | 3 +- src/kernel/arch/amd64/interrupts/isr.c | 5 +- 5 files changed, 101 insertions(+), 30 deletions(-) (limited to 'src/kernel/arch') diff --git a/src/kernel/arch/amd64/driver/ps2.c b/src/kernel/arch/amd64/driver/ps2.c index 7ed369b..1ddd27a 100644 --- a/src/kernel/arch/amd64/driver/ps2.c +++ b/src/kernel/arch/amd64/driver/ps2.c @@ -7,31 +7,106 @@ #include #include -static volatile uint8_t backlog_buf[64]; -static volatile ring_t backlog = {(void*)backlog_buf, sizeof backlog_buf, 0, 0}; +static const int PS2 = 0x60; + +static volatile uint8_t kb_buf[64]; +static volatile ring_t kb_backlog = {(void*)kb_buf, sizeof kb_buf, 0, 0}; + +static volatile uint8_t mouse_buf[64]; +static volatile ring_t mouse_backlog = {(void*)mouse_buf, sizeof mouse_buf, 0, 0}; static void accept(struct vfs_request *req); static bool is_ready(struct vfs_backend *self); static struct vfs_request *kb_queue = NULL; +static struct vfs_request *mouse_queue = NULL; static struct vfs_backend backend = BACKEND_KERN(is_ready, accept); -void ps2_init(void) { vfs_mount_root_register("/ps2", &backend); } +static void wait_out(void) { + uint8_t status; + do { + status = port_in8(PS2 + 4); + } while (status & 2); +} + +static void wait_in(void) { + uint8_t status; + do { + status = port_in8(PS2 + 4); + } while (!(status & 1)); +} + +void ps2_init(void) { + vfs_mount_root_register("/ps2", &backend); + + uint8_t compaq, ack; + wait_out(); + port_out8(PS2 + 4, 0x20); /* get compaq status */ + + wait_in(); + compaq = port_in8(PS2); + compaq |= 1 << 1; /* enable IRQ12 */ + compaq &= ~(1 << 5); /* enable mouse clock */ + + wait_out(); + port_out8(PS2 + 4, 0x60); /* set compaq status */ + + wait_out(); + port_out8(PS2, compaq); + + wait_out(); + port_out8(PS2 + 4, 0xD4); + wait_out(); + port_out8(PS2, 0xF4); /* packet streaming */ + wait_in(); + ack = port_in8(PS2); + assert(ack == 0xFA); +} void ps2_irq(void) { - ring_put1b((void*)&backlog, port_in8(0x60)); - if (kb_queue) { - accept(kb_queue); - kb_queue = kb_queue->postqueue_next; - vfs_backend_tryaccept(&backend); + for (;;) { + uint64_t status = port_in8(PS2 + 4); + if (!(status & 1)) break; /* read while data available */ + if (status & (1 << 5)) { + ring_put1b((void*)&mouse_backlog, port_in8(PS2)); + if (mouse_queue) { + accept(mouse_queue); + mouse_queue = mouse_queue->postqueue_next; + vfs_backend_tryaccept(&backend); + } + } else { + ring_put1b((void*)&kb_backlog, port_in8(PS2)); + if (kb_queue) { + accept(kb_queue); + kb_queue = kb_queue->postqueue_next; + vfs_backend_tryaccept(&backend); + } + } } } enum { H_ROOT, H_KB, + H_MOUSE, }; +static void read_backlog(struct vfs_request *req, ring_t *r, struct vfs_request **queue) { + if (ring_size(r) == 0) { + /* nothing to read, join queue */ + assert(!req->postqueue_next); + while (*queue) queue = &(*queue)->postqueue_next; + *queue = req; + } else if (req->caller) { + int len = req->output.len; + if (len < 0) len = 0; + len = ring_to_virt(r, req->caller->pages, req->output.buf, len); + vfsreq_finish_short(req, len); + } else { + vfsreq_finish_short(req, -1); + } +} + static void accept(struct vfs_request *req) { // when you fix something here go also fix it in the COM1 driver int ret; @@ -42,29 +117,21 @@ static void accept(struct vfs_request *req) { vfsreq_finish_short(req, H_ROOT); } else if (req->input.len == 3 && !memcmp(req->input.buf_kern, "/kb", 3)) { vfsreq_finish_short(req, H_KB); + } else if (req->input.len == 6 && !memcmp(req->input.buf_kern, "/mouse", 6)) { + vfsreq_finish_short(req, H_MOUSE); } else { vfsreq_finish_short(req, -1); } break; case VFSOP_READ: if ((long __force)req->id == H_ROOT) { - const char data[] = "kb"; + const char data[] = "kb\0mouse"; ret = req_readcopy(req, data, sizeof data); vfsreq_finish_short(req, ret); } else if ((long __force)req->id == H_KB) { - if (ring_size((void*)&backlog) == 0) { - /* nothing to read, join queue */ - assert(!req->postqueue_next); - struct vfs_request **slot = &kb_queue; - while (*slot) slot = &(*slot)->postqueue_next; - *slot = req; - } else if (req->caller) { - if (ret < 0) ret = 0; - ret = ring_to_virt((void*)&backlog, req->caller->pages, req->output.buf, req->output.len); - vfsreq_finish_short(req, ret); - } else { - vfsreq_finish_short(req, -1); - } + read_backlog(req, (void*)&kb_backlog, &kb_queue); + } else if ((long __force)req->id == H_MOUSE) { + read_backlog(req, (void*)&mouse_backlog, &mouse_queue); } else panic_invalid_state(); break; default: diff --git a/src/kernel/arch/amd64/driver/serial.c b/src/kernel/arch/amd64/driver/serial.c index d8ee90b..921e140 100644 --- a/src/kernel/arch/amd64/driver/serial.c +++ b/src/kernel/arch/amd64/driver/serial.c @@ -80,8 +80,8 @@ static void accept(struct vfs_request *req) { while (*slot) slot = &(*slot)->postqueue_next; *slot = req; } else if (req->caller) { - if (ret < 0) ret = 0; ret = ring_to_virt((void*)&backlog, req->caller->pages, req->output.buf, req->output.len); + // TODO output.len can overflow here vfsreq_finish_short(req, ret); } else { vfsreq_finish_short(req, -1); diff --git a/src/kernel/arch/amd64/interrupts/irq.c b/src/kernel/arch/amd64/interrupts/irq.c index 9872ec7..1760825 100644 --- a/src/kernel/arch/amd64/interrupts/irq.c +++ b/src/kernel/arch/amd64/interrupts/irq.c @@ -23,13 +23,15 @@ void irq_init(void) { port_out8(PIC1+1, 0x1); port_out8(PIC2+1, 0x1); - uint8_t mask = 0xff; + uint16_t mask = 0xffff; mask &= ~(1 << IRQ_PIT); - mask &= ~(1 << IRQ_PS2); + mask &= ~(1 << 2); // cascade + mask &= ~(1 << IRQ_PS2KB); mask &= ~(1 << IRQ_COM1); + mask &= ~(1 << IRQ_PS2MOUSE); - port_out8(PIC1+1, mask); - port_out8(PIC2+1, 0xff); + port_out8(PIC1+1, mask & 0xff); + port_out8(PIC2+1, (mask >> 8) & 0xff); pit_init(); } diff --git a/src/kernel/arch/amd64/interrupts/irq.h b/src/kernel/arch/amd64/interrupts/irq.h index 2a4b12d..3243224 100644 --- a/src/kernel/arch/amd64/interrupts/irq.h +++ b/src/kernel/arch/amd64/interrupts/irq.h @@ -4,8 +4,9 @@ #define IRQ_IBASE 0x20 #define IRQ_PIT 0 -#define IRQ_PS2 1 +#define IRQ_PS2KB 1 #define IRQ_COM1 4 +#define IRQ_PS2MOUSE 12 void irq_init(void); void irq_eoi(uint8_t line); diff --git a/src/kernel/arch/amd64/interrupts/isr.c b/src/kernel/arch/amd64/interrupts/isr.c index 0bfd865..d1c2b26 100644 --- a/src/kernel/arch/amd64/interrupts/isr.c +++ b/src/kernel/arch/amd64/interrupts/isr.c @@ -34,9 +34,10 @@ void isr_stage3(int interrupt, uint64_t *stackframe) { irq_eoi(IRQ_PIT); return; - case IRQ_IBASE + IRQ_PS2: + case IRQ_IBASE + IRQ_PS2KB: + case IRQ_IBASE + IRQ_PS2MOUSE: ps2_irq(); - irq_eoi(IRQ_PS2); + irq_eoi(interrupt - IRQ_IBASE); return; case IRQ_IBASE + IRQ_COM1: -- cgit v1.2.3