From 5e8cc93aaf1173688852acaa0825698c2dc0cb3f Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 10 May 2018 03:47:35 +0300 Subject: [PATCH] added PS/2 mouse code --- src/asmops.h | 1 + src/contty.c | 25 ++++++++- src/contty.h | 2 + src/kbregs.h | 74 ++++++++++++++++++++++++++ src/keyb.c | 50 ++++++++++++++++-- src/keyb.h | 10 ++++ src/kmain.c | 8 +-- src/pci.c | 7 +++ src/psaux.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/psaux.h | 32 ++++++++++++ src/serial.c | 5 ++ src/startup.s | 1 + src/test/vbetest.c | 91 +++++++++++++++++++++++++++++++- 13 files changed, 443 insertions(+), 10 deletions(-) create mode 100644 src/kbregs.h create mode 100644 src/psaux.c create mode 100644 src/psaux.h diff --git a/src/asmops.h b/src/asmops.h index dbe7ec8..1f42767 100644 --- a/src/asmops.h +++ b/src/asmops.h @@ -74,6 +74,7 @@ static inline uint32_t inl(uint16_t port) "outl %0, %1\n\t" \ :: "a" ((uint32_t)(src)), "dN" ((uint16_t)(port))) +/* delay for about 1us */ #define iodelay() outb(0, 0x80) diff --git a/src/contty.c b/src/contty.c index 606072c..6601ce8 100644 --- a/src/contty.c +++ b/src/contty.c @@ -17,6 +17,7 @@ along with this program. If not, see . */ #include #include +#include #include "contty.h" #include "serial.h" #include "asmops.h" @@ -145,8 +146,7 @@ void con_putchar(int c) break; default: - ptr = (uint16_t*)TEXT_ADDR; - ptr[(cursor_y + start_line) * NCOLS + cursor_x] = VMEM_CHAR(c, txattr); + con_putchar_scr(cursor_x, cursor_y, c); if(++cursor_x >= NCOLS) { linefeed(); @@ -161,6 +161,27 @@ void con_putchar(int c) #endif } +void con_putchar_scr(int x, int y, int c) +{ + uint16_t *ptr = (uint16_t*)TEXT_ADDR; + ptr[(y + start_line) * NCOLS + x] = VMEM_CHAR(c, txattr); +} + +void con_printf(int x, int y, const char *fmt, ...) +{ + va_list ap; + char buf[81]; + char *ptr = buf; + + va_start(ap, fmt); + vsnprintf(buf, 80, fmt, ap); + va_end(ap); + + while(*ptr && x < 80) { + con_putchar_scr(x++, y, *ptr++); + } +} + static void scroll(void) { int new_line; diff --git a/src/contty.h b/src/contty.h index b9b04da..66d9fb5 100644 --- a/src/contty.h +++ b/src/contty.h @@ -26,4 +26,6 @@ void con_bgcolor(int c); void con_clear(void); void con_putchar(int c); +void con_putchar_scr(int x, int y, int c); + #endif /* CONTTY_H_ */ diff --git a/src/kbregs.h b/src/kbregs.h new file mode 100644 index 0000000..abf6524 --- /dev/null +++ b/src/kbregs.h @@ -0,0 +1,74 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef KBREGS_H_ +#define KBREGS_H_ + +#define KB_IRQ 1 +#define PSAUX_IRQ 12 + +#define KB_DATA_PORT 0x60 +#define KB_CMD_PORT 0x64 +#define KB_STATUS_PORT 0x64 + +#define KB_ACK 0xfa +#define KB_NACK 0xfe + +#define KB_STAT_OUTBUF_FULL 0x01 +#define KB_STAT_INBUF_FULL 0x02 +#define KB_STAT_SYSFLAG 0x04 +#define KB_STAT_CMD 0x08 +#define KB_STAT_ACTIVE 0x10 +#define KB_STAT_AUX 0x20 +#define KB_STAT_TIMEOUT 0x40 +#define KB_STAT_PAR_ERROR 0x80 + +/* keyboard commands */ +#define KB_CMD_GET_CMDBYTE 0x20 +#define KB_CMD_SET_CMDBYTE 0x60 +#define KB_CMD_AUX_ENABLE 0xa8 +#define KB_CMD_READ_OUTPORT 0xd0 +#define KB_CMD_WRITE_OUTPORT 0xd1 +#define KB_CMD_PSAUX 0xd4 +#define KB_CMD_PULSE_RESET 0xfe + +/* controller command byte bits */ +#define KB_CCB_KB_INTREN 0x01 +#define KB_CCB_AUX_INTREN 0x02 +#define KB_CCB_SYSFLAG 0x04 +#define KB_CCB_KB_DISABLE 0x10 +#define KB_CCB_AUX_DISABLE 0x20 +#define KB_CCB_KB_XLAT 0x40 + +/* psaux commands (use with d4 prefix) */ +#define AUX_CMD_ENABLE 0xf4 +#define AUX_CMD_DEFAULTS 0xf6 + +#define AUX_PKT0_LEFTBN 0x01 +#define AUX_PKT0_RIGHTBN 0x02 +#define AUX_PKT0_MIDDLEBN 0x04 +#define AUX_PKT0_ALWAYS1 0x08 +#define AUX_PKT0_XSIGN 0x10 +#define AUX_PKT0_YSIGN 0x20 +#define AUX_PKT0_XOVF 0x40 +#define AUX_PKT0_YOVF 0x80 + +#define AUX_PKT0_OVF_BITS (AUX_PKT0_XOVF | AUX_PKT0_YOVF) +#define AUX_PKT0_BUTTON_BITS \ + (AUX_PKT0_LEFTBN | AUX_PKT0_RIGHTBN | AUX_PKT0_MIDDLEBN) + +#endif /* KBREGS_H_ */ diff --git a/src/keyb.c b/src/keyb.c index a63312e..0b61871 100644 --- a/src/keyb.c +++ b/src/keyb.c @@ -15,13 +15,13 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include #include #include "keyb.h" #include "intr.h" #include "asmops.h" +#include "kbregs.h" -#define KB_IRQ 1 -#define KB_PORT 0x60 /* table with rough translations from set 1 scancodes to ASCII-ish */ static int scantbl[] = { @@ -115,12 +115,56 @@ void kb_putback(int key) buffer[buf_ridx] = key; } +int kb_wait_write(void) +{ + int i; + for(i=0; i<32768; i++) { + if(!(inb(KB_STATUS_PORT) & KB_STAT_INBUF_FULL)) { + return 1; + } + iodelay(); + } + /*printf("kb_wait_write timeout\n");*/ + return 0; +} + +int kb_wait_read(void) +{ + int i; + for(i=0; i<32768; i++) { + if((inb(KB_STATUS_PORT) & KB_STAT_OUTBUF_FULL)) { + return 1; + } + iodelay(); + } + /*printf("kb_wait_read timeout\n");*/ + return 0; +} + +void kb_send_cmd(unsigned char cmd) +{ + kb_wait_write(); + outb(cmd, KB_CMD_PORT); +} + +void kb_send_data(unsigned char data) +{ + kb_wait_write(); + outb(data, KB_DATA_PORT); +} + +unsigned char kb_read_data(void) +{ + kb_wait_read(); + return inb(KB_DATA_PORT); +} + static void kbintr() { unsigned char code; int key, press; - code = inb(KB_PORT); + code = inb(KB_DATA_PORT); if(code >= 128) { press = 0; diff --git a/src/keyb.h b/src/keyb.h index bfa58e8..a5297e4 100644 --- a/src/keyb.h +++ b/src/keyb.h @@ -56,4 +56,14 @@ int kb_getkey(void); void kb_putback(int key); +/* returns 1 if the keyboard controller is ready to read/write + * returns 0 if the wait times out + */ +int kb_wait_write(void); +int kb_wait_read(void); + +void kb_send_cmd(unsigned char cmd); +void kb_send_data(unsigned char data); +unsigned char kb_read_data(void); + #endif /* KEYB_H_ */ diff --git a/src/kmain.c b/src/kmain.c index 2404033..3c256a6 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -22,6 +22,7 @@ along with this program. If not, see . #include "intr.h" #include "mem.h" #include "keyb.h" +#include "psaux.h" #include "timer.h" #include "contty.h" #include "video.h" @@ -38,6 +39,7 @@ void pcboot_main(void) con_init(); kb_init(); + init_psaux(); init_mem(); @@ -67,13 +69,13 @@ void pcboot_main(void) break; } if(isprint(c)) { - printf("key: %d '%c' \n", c, (char)c); + printf("key: %d '%c'\n", c, (char)c); } else { - printf("key: %d \n", c); + printf("key: %d\n", c); } } if((nticks % 250) == 0) { - printf("ticks: %ld\r", nticks); + con_printf(71, 0, "[%ld]", nticks); } } } diff --git a/src/pci.c b/src/pci.c index c5cd65e..7ebb3c5 100644 --- a/src/pci.c +++ b/src/pci.c @@ -19,6 +19,7 @@ along with this program. If not, see . #include #include #include "pci.h" +#include "intr.h" #include "int86.h" #include "asmops.h" #include "panic.h" @@ -69,12 +70,18 @@ static uint32_t (*cfg_read32)(int, int, int, int); void init_pci(void) { int i, count = 0; + int intrflag; struct int86regs regs; + intrflag = get_intr_flag(); + memset(®s, 0, sizeof regs); regs.eax = 0xb101; int86(0x1a, ®s); + /* restore interrupt state in case bios changed it */ + set_intr_flag(intrflag); + /* PCI BIOS present if CF=0, AH=0, and EDX has the "PCI " sig FOURCC */ if((regs.flags & FLAGS_CARRY) || (regs.eax & 0xff00) || regs.edx != PCI_SIG) { printf("No PCI BIOS present\n"); diff --git a/src/psaux.c b/src/psaux.c new file mode 100644 index 0000000..d6d5f2e --- /dev/null +++ b/src/psaux.c @@ -0,0 +1,147 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include "psaux.h" +#include "intr.h" +#include "asmops.h" +#include "keyb.h" +#include "kbregs.h" + +static void init_mouse(); +static void psaux_intr(); + +static int mx, my; +static unsigned int bnstate; +static int present; +static int bounds[4]; + +void init_psaux(void) +{ + interrupt(IRQ_TO_INTR(12), psaux_intr); + + set_mouse_bounds(0, 0, 319, 199); + + init_mouse(); +} + +static void init_mouse() +{ + unsigned char val; + + kb_send_cmd(KB_CMD_AUX_ENABLE); + if(kb_wait_read()) { + val = kb_read_data(); + printf("aux enable: %02x\n", (unsigned int)val); + } + + kb_send_cmd(KB_CMD_GET_CMDBYTE); + val = kb_read_data(); + val &= ~KB_CCB_AUX_DISABLE; + val |= KB_CCB_AUX_INTREN; + kb_send_cmd(KB_CMD_SET_CMDBYTE); + kb_send_data(val); + + if(kb_wait_read()) { + val = kb_read_data(); + printf("set cmdbyte: %02x\n", (unsigned int)val); + } + + kb_send_cmd(KB_CMD_PSAUX); + kb_send_data(AUX_CMD_DEFAULTS); + val = kb_read_data(); + + kb_send_cmd(KB_CMD_PSAUX); + kb_send_data(AUX_CMD_ENABLE); + val = kb_read_data(); + + present = (val == KB_ACK) ? 1 : 0; + printf("init_mouse: %spresent\n", present ? "" : "not "); +} + +int have_mouse(void) +{ + return present; +} + +void set_mouse_bounds(int x0, int y0, int x1, int y1) +{ + bounds[0] = x0; + bounds[1] = y0; + bounds[2] = x1; + bounds[3] = y1; +} + +unsigned int mouse_state(int *xp, int *yp) +{ + *xp = mx; + *yp = my; + return bnstate; +} + +static void psaux_intr() +{ + static unsigned char data[3]; + static int idx; + int dx, dy; + + if(!(inb(KB_STATUS_PORT) & KB_STAT_AUX)) { + /* no mouse data pending, ignore interrupt */ + return; + } + + data[idx] = kb_read_data(); + if(++idx >= 3) { + idx = 0; + + if(data[0] & AUX_PKT0_OVF_BITS) { + /* consensus seems to be that if overflow bits are set, something is + * fucked, and it's best to re-initialize the mouse + */ + init_mouse(); + } else { + /* + printf("psaux data packet: %02x %02x %02x\n", (unsigned int)data[0], + (unsigned int)data[1], (unsigned int)data[2]); + */ + + bnstate = data[0] & AUX_PKT0_BUTTON_BITS; + dx = data[1]; + dy = data[2]; + + if(data[0] & AUX_PKT0_XSIGN) { + dx |= 0xffffff00; + } + if(data[0] & AUX_PKT0_YSIGN) { + dy |= 0xffffff00; + } + + mx += dx; + my -= dy; + + if(mx < bounds[0]) mx = bounds[0]; + if(mx > bounds[2]) mx = bounds[2]; + if(my < bounds[1]) my = bounds[1]; + if(my > bounds[3]) my = bounds[3]; + + /* + printf("mouse: %d,%d [%c%c%c]\n", mx, my, bnstate & AUX_PKT0_LEFTBN ? '1' : '0', + bnstate & AUX_PKT0_MIDDLEBN ? '1' : '0', bnstate & AUX_PKT0_RIGHTBN ? '1' : '0'); + */ + } + } +} diff --git a/src/psaux.h b/src/psaux.h new file mode 100644 index 0000000..bbaf96e --- /dev/null +++ b/src/psaux.h @@ -0,0 +1,32 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef PSAUX_H_ +#define PSAUX_H_ + +#define MOUSE_LBN_BIT 1 +#define MOUSE_RBN_BIT 2 +#define MOUSE_MBN_BIT 4 + +void init_psaux(void); + +int have_mouse(void); + +void set_mouse_bounds(int x0, int y0, int x1, int y1); +unsigned int mouse_state(int *xp, int *yp); + +#endif /* PSAUX_H_ */ diff --git a/src/serial.c b/src/serial.c index 215276c..792f296 100644 --- a/src/serial.c +++ b/src/serial.c @@ -228,6 +228,11 @@ static int can_send(int fd) void ser_putc(int fd, char c) { int base = ports[fd].base; + + if(c == '\n') { + ser_putc(fd, '\r'); + } + while(!can_send(fd)); while((inb(base + UART_MSTAT) & MST_CTS) == 0); outb(c, base + UART_DATA); diff --git a/src/startup.s b/src/startup.s index 0a36b67..ef3cd38 100644 --- a/src/startup.s +++ b/src/startup.s @@ -24,6 +24,7 @@ .extern kb_getkey # move the stack to the top of the conventional memory + cli movl $0x80000, %esp # zero the BSS section diff --git a/src/test/vbetest.c b/src/test/vbetest.c index 91a8c8c..1133dec 100644 --- a/src/test/vbetest.c +++ b/src/test/vbetest.c @@ -3,13 +3,38 @@ #include "video.h" #include "asmops.h" #include "keyb.h" +#include "psaux.h" #include "contty.h" +static void draw_cursor(int x, int y, uint16_t col); + static uint16_t *framebuf; +#define CURSOR_XSZ 12 +#define CURSOR_YSZ 16 +static uint16_t cursor[] = { + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0x0001, 0xffff, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0001, 0xffff, 0xffff, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0001, 0x0001, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + int vbetest(void) { - int i, j, nmodes; + int i, j, nmodes, mx, my; + unsigned int st; struct video_mode vi; uint16_t *fbptr; @@ -51,8 +76,19 @@ int vbetest(void) } } + set_mouse_bounds(0, 0, 639, 479); + + /* empty the kb queue */ while(kb_getkey() != -1); - while(kb_getkey() == -1) { + + for(;;) { + if(kb_getkey() != -1) { + break; + } + + st = mouse_state(&mx, &my); + draw_cursor(mx, my, st & 1 ? 0xf800 : (st & 2 ? 0x7e0 : (st & 4 ? 0x00ff : 0))); + halt_cpu(); } @@ -60,3 +96,54 @@ int vbetest(void) con_clear(); return 0; } + +static void draw_cursor(int x, int y, uint16_t col) +{ + static uint16_t saved[CURSOR_XSZ * CURSOR_YSZ]; + static int saved_x = -1, saved_y, saved_w, saved_h; + + int i, j, w, h; + uint16_t *dest, *src, *savp; + + if(saved_x >= 0) { + dest = framebuf + saved_y * 640 + saved_x; + src = saved; + + for(i=0; i CURSOR_XSZ) w = CURSOR_XSZ; + h = 480 - y; + if(h > CURSOR_YSZ) h = CURSOR_YSZ; + + saved_x = x; + saved_y = y; + saved_w = w; + saved_h = h; + + for(i=0; i