#include #include #include #include #include #include #include // ---------------------------------------------- // Keyboard // ---------------------------------------------- #define PCKBD_BUF_LEN 16 kbd_event_t pckbd_buf[PCKBD_BUF_LEN]; int pckbd_buf_used = 0; bool pckbd_escaped = false; void irq1_handler(registers_t *regs) { uint8_t scancode = inb(0x60); if (scancode == 0xE0) { pckbd_escaped = true; } else { kbd_event_t ev; if (scancode & 0x80) { if (pckbd_escaped) { ev.scancode = scancode; ev.type = KBD_EVENT_KEYRELEASE; } else { ev.scancode = scancode & 0x7F; ev.type = KBD_EVENT_KEYRELEASE; } } else { if (pckbd_escaped) { ev.scancode = scancode | 0x80; ev.type = KBD_EVENT_KEYPRESS; } else { ev.scancode = scancode; ev.type = KBD_EVENT_KEYPRESS; } } if (pckbd_buf_used < PCKBD_BUF_LEN) { pckbd_buf[pckbd_buf_used++] = ev; resume_on(&pckbd_buf); } pckbd_escaped = false; } } // ---- VFS operations bool pckbd_open(fs_node_t *n, int mode); size_t pckbd_read(fs_handle_t *h, size_t offset, size_t len, char *buf); int pckbd_poll(fs_handle_t *h, void** out_wait_obj); void pckbd_close(fs_handle_t *h); int pckbd_ioctl(fs_handle_t *h, int command, void* data); bool pckbd_stat(fs_node_t *n, stat_t *st); fs_node_ops_t pckbd_ops = { .open = pckbd_open, .read = pckbd_read, .write = 0, .readdir = 0, .poll = pckbd_poll, .close = pckbd_close, .ioctl = pckbd_ioctl, .stat = pckbd_stat, .walk = 0, .delete = 0, .move = 0, .create = 0, .dispose = 0, }; void pckbd_setup(fs_t *iofs) { uint8_t a = 0, b = 0; while ((a = inb(0x60)) != b) b = a; idt_set_irq_handler(IRQ1, &irq1_handler); nullfs_add_node(iofs, "/input/pckbd", 0, &pckbd_ops, 0); } bool pckbd_open(fs_node_t *n, int mode) { return (mode == FM_READ); } size_t pckbd_read(fs_handle_t *h, size_t offset, size_t len, char *buf) { int ret = 0; int st = enter_critical(CL_NOINT); while (len - ret >= sizeof(kbd_event_t) && pckbd_buf_used > 0) { memcpy(buf + ret, &pckbd_buf[0], sizeof(kbd_event_t)); for (int i = 1; i < pckbd_buf_used; i++) { pckbd_buf[i-1] = pckbd_buf[i]; } pckbd_buf_used--; ret += sizeof(kbd_event_t); } exit_critical(st); return ret; } int pckbd_poll(fs_handle_t *h, void** out_wait_obj) { if (out_wait_obj) *out_wait_obj = &pckbd_buf; return (pckbd_buf_used > 0 ? SEL_READ : 0); } void pckbd_close(fs_handle_t *h) { return; // nothing to do } int pckbd_ioctl(fs_handle_t *h, int command, void* data) { if (command == IOCTL_KBD_SET_LEDS) { uint8_t leds = (uint32_t)data & 0x07; outb(0x60, leds); return 1; } return 0; } bool pckbd_stat(fs_node_t *n, stat_t *st) { st->type = FT_CHARDEV; st->size = 0; st->access = FM_READ; return true; } // ---------------------------------------------- // Mouse // ---------------------------------------------- #define PCMOUSE_BUF_LEN 64 mouse_event_t pcmouse_buf[PCMOUSE_BUF_LEN]; int pcmouse_buf_used = 0; int mouse_cycle = 0; int8_t mouse_byte[4]; void irq12_handler(registers_t *regs) { if (mouse_cycle == 0) { mouse_byte[0] = inb(0x60); mouse_cycle = 1; } else if (mouse_cycle == 1) { mouse_byte[1] = inb(0x60); mouse_cycle = 2; } else if (mouse_cycle == 2) { mouse_byte[2] = inb(0x60); mouse_cycle = 0; if (mouse_byte[0] & (0x80 | 0x40)) return; // overflow bit is set if (pcmouse_buf_used >= PCMOUSE_BUF_LEN) return; mouse_event_t e; e.delta_x = mouse_byte[1]; e.delta_y = mouse_byte[2]; if (mouse_byte[0] & 0x10) e.delta_x |= 0xFF00; if (mouse_byte[0] & 0x20) e.delta_y |= 0xFF00; e.delta_wheel = 0; e.lbtn = ((mouse_byte[0] & 0x01) != 0); e.rbtn = ((mouse_byte[0] & 0x02) != 0); e.midbtn = ((mouse_byte[0] & 0x04) != 0); pcmouse_buf[pcmouse_buf_used++] = e; resume_on(&pcmouse_buf); } } static inline void mouse_wait(int a_type) { size_t _time_out = 100000; if (a_type == 0) { while(_time_out--) { if ((inb(0x64) & 1)==1) return; } } else { while(_time_out--) { if ((inb(0x64) & 2)==0) return; } } } static inline void mouse_write(uint8_t a_write) { mouse_wait(1); outb(0x64, 0xD4); mouse_wait(1); outb(0x60, a_write); } static inline uint8_t mouse_read() { mouse_wait(0); return inb(0x60); } void pcmouse_setup_device() { // Enable mouse device mouse_wait(1); outb(0x64, 0xA8); // Enable interrupts mouse_wait(1); outb(0x64, 0x20); mouse_wait(0); uint8_t status = (inb(0x60) | 2); mouse_wait(1); outb(0x64, 0x60); mouse_wait(0); outb(0x60, status); // Tell mouse to use default settings mouse_write(0xF6); mouse_read(); // Enable mouse mouse_write(0xF4); mouse_read(); } bool pcmouse_open(fs_node_t *n, int mode); size_t pcmouse_read(fs_handle_t *h, size_t offset, size_t len, char *buf); int pcmouse_poll(fs_handle_t *h, void** out_wait_obj); void pcmouse_close(fs_handle_t *h); int pcmouse_ioctl(fs_handle_t *h, int command, void* data); bool pcmouse_stat(fs_node_t *n, stat_t *st); fs_node_ops_t pcmouse_ops = { .open = pcmouse_open, .read = pcmouse_read, .write = 0, .readdir = 0, .poll = pcmouse_poll, .close = pcmouse_close, .ioctl = pcmouse_ioctl, .stat = pcmouse_stat, .walk = 0, .delete = 0, .move = 0, .create = 0, .dispose = 0, }; void pcmouse_setup(fs_t *iofs) { pcmouse_setup_device(); idt_set_irq_handler(IRQ12, &irq12_handler); nullfs_add_node(iofs, "/input/pcmouse", 0, &pcmouse_ops, 0); } bool pcmouse_open(fs_node_t *n, int mode) { return (mode == FM_READ); } size_t pcmouse_read(fs_handle_t *h, size_t offset, size_t len, char *buf) { int ret = 0; int st = enter_critical(CL_NOINT); while (len - ret >= sizeof(mouse_event_t) && pcmouse_buf_used > 0) { memcpy(buf + ret, &pcmouse_buf[0], sizeof(mouse_event_t)); for (int i = 1; i < pcmouse_buf_used; i++) { pcmouse_buf[i-1] = pcmouse_buf[i]; } pcmouse_buf_used--; ret += sizeof(mouse_event_t); } exit_critical(st); return ret; } int pcmouse_poll(fs_handle_t *h, void** out_wait_obj) { if (out_wait_obj) *out_wait_obj = &pcmouse_buf; return (pcmouse_buf_used > 0 ? SEL_READ : 0); } void pcmouse_close(fs_handle_t *h) { return; // nothing to do } int pcmouse_ioctl(fs_handle_t *h, int command, void* data) { // No ioctls implemented... return 0; } bool pcmouse_stat(fs_node_t *n, stat_t *st) { st->type = FT_CHARDEV; st->size = 0; st->access = FM_READ; return true; } /* vim: set ts=4 sw=4 tw=0 noet :*/