added PS/2 mouse code
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 10 May 2018 00:47:35 +0000 (03:47 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 10 May 2018 00:47:35 +0000 (03:47 +0300)
13 files changed:
src/asmops.h
src/contty.c
src/contty.h
src/kbregs.h [new file with mode: 0644]
src/keyb.c
src/keyb.h
src/kmain.c
src/pci.c
src/psaux.c [new file with mode: 0644]
src/psaux.h [new file with mode: 0644]
src/serial.c
src/startup.s
src/test/vbetest.c

index dbe7ec8..1f42767 100644 (file)
@@ -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)
 
 
index 606072c..6601ce8 100644 (file)
@@ -17,6 +17,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdio.h>
 #include <string.h>
+#include <stdarg.h>
 #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;
index b9b04da..66d9fb5 100644 (file)
@@ -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 (file)
index 0000000..abf6524
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#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_ */
index a63312e..0b61871 100644 (file)
@@ -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 <https://www.gnu.org/licenses/>.
 */
+#include <stdio.h>
 #include <string.h>
 #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;
index bfa58e8..a5297e4 100644 (file)
@@ -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_ */
index 2404033..3c256a6 100644 (file)
@@ -22,6 +22,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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);
                }
        }
 }
index c5cd65e..7ebb3c5 100644 (file)
--- a/src/pci.c
+++ b/src/pci.c
@@ -19,6 +19,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <string.h>
 #include <inttypes.h>
 #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(&regs, 0, sizeof regs);
        regs.eax = 0xb101;
        int86(0x1a, &regs);
 
+       /* 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 (file)
index 0000000..d6d5f2e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#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 (file)
index 0000000..bbaf96e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#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_ */
index 215276c..792f296 100644 (file)
@@ -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);
index 0a36b67..ef3cd38 100644 (file)
@@ -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
index 91a8c8c..1133dec 100644 (file)
@@ -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<saved_h; i++) {
+                       for(j=0; j<saved_w; j++) {
+                               *dest++ = *src++;
+                       }
+                       src += CURSOR_XSZ - saved_w;
+                       dest += 640 - saved_w;
+               }
+       }
+
+       dest = framebuf + y * 640 + x;
+       src = cursor;
+       savp = saved;
+
+       w = 640 - x;
+       if(w > 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<h; i++) {
+               for(j=0; j<w; j++) {
+                       uint16_t c = *src++;
+                       *savp++ = *dest;
+                       if(c) {
+                               if(c == 1) c = col;
+                               *dest = c;
+                       }
+                       dest++;
+               }
+               src += CURSOR_XSZ - w;
+               dest += 640 - w;
+               savp += CURSOR_XSZ - w;
+       }
+}