summaryrefslogtreecommitdiff
path: root/src/kernel/arch
diff options
context:
space:
mode:
authordzwdz2022-08-07 22:07:27 +0200
committerdzwdz2022-08-07 22:07:27 +0200
commit9a43ead118ec1506848bad9d2bcddfb0fd458552 (patch)
tree295103e04a01e0eaa319d0984c9a74bb50956c4c /src/kernel/arch
parentfbbe8a1cb4c421e9658c5009ecfab6845137587b (diff)
kernel: ps2 mouse support
Diffstat (limited to 'src/kernel/arch')
-rw-r--r--src/kernel/arch/amd64/driver/ps2.c111
-rw-r--r--src/kernel/arch/amd64/driver/serial.c2
-rw-r--r--src/kernel/arch/amd64/interrupts/irq.c10
-rw-r--r--src/kernel/arch/amd64/interrupts/irq.h3
-rw-r--r--src/kernel/arch/amd64/interrupts/isr.c5
5 files changed, 101 insertions, 30 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);
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: