Forráskód Böngészése

feat: bufferred tty reading

greatbridf 2 éve
szülő
commit
551cec8c54

+ 4 - 0
include/kernel/tty.hpp

@@ -12,22 +12,26 @@ public:
 public:
     tty();
     virtual void putchar(char c) = 0;
+    virtual void recvchar(char c) = 0;
     void print(const char* str);
 
     char name[NAME_SIZE];
     types::buffer<types::kernel_ident_allocator> buf;
+    bool echo = true;
 };
 
 class vga_tty : public virtual tty {
 public:
     vga_tty();
     virtual void putchar(char c) override;
+    virtual void recvchar(char c) override;
 };
 
 class serial_tty : public virtual tty {
 public:
     serial_tty(int id);
     virtual void putchar(char c) override;
+    virtual void recvchar(char c) override;
 
 public:
     uint16_t id;

+ 37 - 8
include/types/buffer.hpp

@@ -18,10 +18,10 @@ private:
     size_t count;
 
 private:
-    constexpr char _get_char(void)
+    constexpr char _get_char(char* ptr)
     {
         --count;
-        return *base;
+        return *ptr;
     }
 
     constexpr void _put_char(char c)
@@ -30,12 +30,20 @@ private:
         ++count;
     }
 
-    constexpr void _forward(char*& ptr)
+    constexpr char* _forward(char* ptr)
     {
         if (ptr == end)
-            ptr = start;
+            return start;
+        else
+            return ptr + 1;
+    }
+
+    constexpr char* _backward(char* ptr)
+    {
+        if (ptr == start)
+            return end;
         else
-            ++ptr;
+            return ptr - 1;
     }
 
 public:
@@ -82,14 +90,35 @@ public:
         return count == static_cast<size_t>(end - start + 1);
     }
 
+    constexpr char front(void)
+    {
+        return *base;
+    }
+
+    constexpr char back(void)
+    {
+        return *_backward(head);
+    }
+
     constexpr char get(void)
     {
         // TODO: set error flag
         if (empty())
             return 0xff;
 
-        char c = _get_char();
-        _forward(base);
+        char c = _get_char(base);
+        base = _forward(base);
+        return c;
+    }
+
+    constexpr char pop(void)
+    {
+        // TODO: set error flag
+        if (empty())
+            return 0xff;
+
+        char c = _get_char(_backward(head));
+        head = _backward(head);
         return c;
     }
 
@@ -100,7 +129,7 @@ public:
             return 0xff;
 
         _put_char(c);
-        _forward(head);
+        head = _forward(head);
         return c;
     }
 };

+ 1 - 24
src/kernel/hw/serial.cpp

@@ -61,29 +61,6 @@ void serial_receive_data_interrupt(void)
 {
     while (is_serial_has_data(PORT_SERIAL0)) {
         uint8_t data = serial_read_data(PORT_SERIAL0);
-        char buf[64] = { 0 };
-        switch (data) {
-        case '\r':
-            serial_send_data(PORT_SERIAL0, '\r');
-            serial_send_data(PORT_SERIAL0, '\n');
-            break;
-        // ^?
-        case 0x7f:
-            serial_send_data(PORT_SERIAL0, 0x08);
-            serial_send_data(PORT_SERIAL0, '\x1b');
-            serial_send_data(PORT_SERIAL0, '[');
-            serial_send_data(PORT_SERIAL0, 'K');
-            break;
-        // ^U
-        case 0x15:
-            serial_send_data(PORT_SERIAL0, '\r');
-            serial_send_data(PORT_SERIAL0, '\x1b');
-            serial_send_data(PORT_SERIAL0, '[');
-            serial_send_data(PORT_SERIAL0, '2');
-            serial_send_data(PORT_SERIAL0, 'K');
-        default:
-            serial_send_data(PORT_SERIAL0, data);
-            break;
-        }
+        console->recvchar(data);
     }
 }

+ 1 - 0
src/kernel/interrupt.cpp

@@ -237,6 +237,7 @@ extern "C" void irq3_handler(void)
 }
 extern "C" void irq4_handler(void)
 {
+    // TODO: register interrupt handler in serial port driver
     serial_receive_data_interrupt();
     asm_outb(PORT_PIC1_COMMAND, PIC_EOI);
 }

+ 50 - 0
src/kernel/tty.cpp

@@ -37,3 +37,53 @@ void vga_tty::putchar(char c)
     vc.c = c;
     vga_put_char(&vc);
 }
+
+void vga_tty::recvchar(char c)
+{
+    // TODO: keyboard scan code
+    buf.put(c);
+}
+
+void serial_tty::recvchar(char c)
+{
+    switch (c) {
+    case '\r':
+        buf.put('\n');
+        if (echo) {
+            serial_send_data(PORT_SERIAL0, '\r');
+            serial_send_data(PORT_SERIAL0, '\n');
+        }
+        // TODO: notify
+        break;
+    // ^?: backspace
+    case 0x7f:
+        if (!buf.empty() && buf.back() != '\n')
+            buf.pop();
+
+        if (echo) {
+            serial_send_data(PORT_SERIAL0, 0x08);
+            serial_send_data(PORT_SERIAL0, '\x1b');
+            serial_send_data(PORT_SERIAL0, '[');
+            serial_send_data(PORT_SERIAL0, 'K');
+        }
+        break;
+    // ^U: clear the line
+    case 0x15:
+        while (!buf.empty() && buf.back() != '\n')
+            buf.pop();
+
+        if (echo) {
+            serial_send_data(PORT_SERIAL0, '\r');
+            serial_send_data(PORT_SERIAL0, '\x1b');
+            serial_send_data(PORT_SERIAL0, '[');
+            serial_send_data(PORT_SERIAL0, '2');
+            serial_send_data(PORT_SERIAL0, 'K');
+        }
+        break;
+    default:
+        buf.put(c);
+        if (echo)
+            serial_send_data(PORT_SERIAL0, c);
+        break;
+    }
+}