diff options
author | dzwdz | 2022-08-07 22:07:27 +0200 |
---|---|---|
committer | dzwdz | 2022-08-07 22:07:27 +0200 |
commit | 9a43ead118ec1506848bad9d2bcddfb0fd458552 (patch) | |
tree | 295103e04a01e0eaa319d0984c9a74bb50956c4c /src/kernel/arch/amd64/driver | |
parent | fbbe8a1cb4c421e9658c5009ecfab6845137587b (diff) |
kernel: ps2 mouse support
Diffstat (limited to 'src/kernel/arch/amd64/driver')
-rw-r--r-- | src/kernel/arch/amd64/driver/ps2.c | 111 | ||||
-rw-r--r-- | src/kernel/arch/amd64/driver/serial.c | 2 |
2 files changed, 90 insertions, 23 deletions
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 <kernel/vfs/request.h> #include <shared/mem.h> -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); |