feat: capability list to enable greater flexibility of devices
authorMinep <lunaixsky@qq.com>
Mon, 11 Dec 2023 00:56:18 +0000 (00:56 +0000)
committerMinep <lunaixsky@qq.com>
Mon, 11 Dec 2023 00:56:18 +0000 (00:56 +0000)
feat: implement termios interface in LunaClib
fix: strange behaviour refered as double mounting and double-mkdir
fix: a mis-used of fpos parameter in some device file read/write invocation
fix: some bugs in user program
chore: edit readme

30 files changed:
README.md
lunaix-os/GRUB_TEMPLATE
lunaix-os/config-grub.sh
lunaix-os/hal/char/serial.c
lunaix-os/hal/char/uart/16550.h
lunaix-os/hal/char/uart/16550_base.c
lunaix-os/hal/term/console.c
lunaix-os/hal/term/lcntls/lcntl.c
lunaix-os/hal/term/term.c
lunaix-os/hal/term/term_io.c
lunaix-os/includes/hal/serial.h
lunaix-os/includes/hal/term.h
lunaix-os/includes/lunaix/device.h
lunaix-os/includes/lunaix/syslog.h
lunaix-os/includes/usr/lunaix/dirent_defs.h
lunaix-os/includes/usr/lunaix/serial.h
lunaix-os/includes/usr/lunaix/term.h
lunaix-os/kernel/device/capability.c [new file with mode: 0644]
lunaix-os/kernel/device/device.c
lunaix-os/kernel/ds/rbuffer.c
lunaix-os/kernel/fs/mount.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/tty/lxconsole.c
lunaix-os/makefile
lunaix-os/usr/cat/main.c
lunaix-os/usr/init/init.c
lunaix-os/usr/libc/includes/termios.h [new file with mode: 0644]
lunaix-os/usr/libc/src/termios.c [new file with mode: 0644]
lunaix-os/usr/ls/ls.c
lunaix-os/usr/sh/sh.c

index 213f2132f29818052b9514bf9daf7c30a501a198..bb7f24fc627cc3b7938e88f573657d542c0d120a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -108,6 +108,24 @@ make CX_PREFIX=i686-linux-gnu- all
 
 **※:由于在`-O2`模式下,GCC会进行CSE优化,这导致LunaixOS会出现一些非常奇怪、离谱的bug,从而影响到基本运行。具体原因有待调查。**
 
+### 4.4 设置内核启动参数
+
+在 make 的时候通过`CMDLINE`变量可以设置内核启动参数列表。该列表可以包含多个参数,通过一个或多个空格来分割。每个参数可以为键值对 `<key>=<val>` 或者是开关标志位 `<flag>`。目前 Lunaix 支持以下参数:
+
++ `console=<dev>` 设置系统终端的输入输出设备(tty设备)。其中 `<dev>` 是设备文件路径 (注意,这里的设备文件路径是针对Lunaix,而非Linux)。关于LunaixOS设备文件系统的介绍可参考 Lunaix Wiki(WIP)
+
+如果`CMDLINE`未指定,则将会载入默认参数:
+
+```
+console=/dev/ttyFB0
+```
+
+其中,`/dev/ttyFB0` 指向基于VGA文本模式的tty设备,也就是平时启动QEMU时看到的黑色窗口。
+
+当然,读者也可以使用 `/dev/ttyS0` 来作为默认tty设备,来验证 Lunaix 的灵活性与兼容性。该路径指向第一个串口设备。可以通过telnet协议在`12345`端口上进行访问——端口号可以自行修改QEMU启动参数(位于:`makeinc/qemu.mkinc`)来变更。
+
+**注意:** 根据操作系统和键盘布局的不同,telnet客户端对一些关键键位的映射(如退格,回车)可能有所差别(如某些版本的Linux会将退格键映射为`0x7f`,也就是ASCII的`<DEL>`字符,而非我们熟知`0x08`)。如果读者想要通过串口方式把玩Lunaix,请修改`usr/init/init.c`里面的终端初始化代码,将`VERASE`设置为正确的映射(修改方式可以参考 POSIX termios 的使用方式。由于Lunaix的终端接口的实现是完全兼容POSIX的,读者可以直接去查阅Linux自带的帮助`man termios`,无需作任何的转换)
+
 ## 5. 运行,分支以及 Issue
 
 ### 5.1 虚拟磁盘(非必须)
index c33d45f96b921416ffcd3c5b24b540d0dacd0a09..db98366aafb1a36d8e3cfb1a461b2c6f53eb9e11 100644 (file)
@@ -2,6 +2,6 @@ default=0
 timeout=0
 
 menuentry "$_OS_NAME" {
-       multiboot /boot/kernel.bin console=/dev/vcon
+       multiboot /boot/kernel.bin $KCMD
        module --nounzip /boot/modksyms modksyms
 }
\ No newline at end of file
index ff4d4b639daba06f25bfbb5a3695213359873bf0..956cb4f7e50507ebaaa67008eeb79f313ff0091c 100755 (executable)
@@ -1,5 +1,3 @@
 #!/usr/bin/bash
 
-export _OS_NAME=$1
-
-cat GRUB_TEMPLATE | envsubst > "$2"
\ No newline at end of file
+cat GRUB_TEMPLATE | envsubst > "$1"
\ No newline at end of file
index 528f1417d692cb6abecf95c5282eb4d92891673d..d93ff398b81231019595c332bf8daaae1ad5e1a6 100644 (file)
@@ -6,6 +6,7 @@
 #include <sys/mm/mempart.h>
 
 #include <hal/serial.h>
+#include <hal/term.h>
 
 #define lock_sdev(sdev) device_lock((sdev)->dev)
 #define unlock_sdev(sdev) device_unlock((sdev)->dev)
@@ -143,41 +144,41 @@ serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
 }
 
 static int
-__serial_read(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_read(struct device* dev, void* buf, off_t fpos, size_t len)
 {
-    return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], len);
+    return serial_readbuf(serial_device(dev), (u8_t*)buf, len);
 }
 
 static int
-__serial_read_async(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_read_async(struct device* dev, void* buf, off_t fpos, size_t len)
 {
     return serial_readbuf_nowait(
-        serial_device(dev), &((u8_t*)buf)[offset], len);
+        serial_device(dev), (u8_t*)buf, len);
 }
 
 static int
-__serial_read_page(struct device* dev, void* buf, size_t offset)
+__serial_read_page(struct device* dev, void* buf, off_t fpos)
 {
-    return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
+    return serial_readbuf(serial_device(dev), (u8_t*)buf, MEM_PAGE);
 }
 
 static int
-__serial_write(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_write(struct device* dev, void* buf, off_t fpos, size_t len)
 {
-    return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], len);
+    return serial_writebuf(serial_device(dev), (u8_t*)buf, len);
 }
 
 static int
-__serial_write_async(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_write_async(struct device* dev, void* buf, off_t fpos, size_t len)
 {
     return serial_writebuf_nowait(
-        serial_device(dev), &((u8_t*)buf)[offset], len);
+        serial_device(dev), (u8_t*)buf, len);
 }
 
 static int
-__serial_write_page(struct device* dev, void* buf, size_t offset)
+__serial_write_page(struct device* dev, void* buf, off_t fpos)
 {
-    return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
+    return serial_writebuf(serial_device(dev), (u8_t*)buf, MEM_PAGE);
 }
 
 static int
@@ -200,6 +201,38 @@ __serial_poll_event(struct device* dev)
     return sdev->dev->poll_evflags;
 }
 
+static void sdev_execmd(struct serial_dev* sdev, u32_t req, ...)
+{
+    va_list args;
+    va_start(args, req);
+
+    sdev->exec_cmd(sdev, req, args);
+
+    va_end(args);
+}
+
+static void
+__serial_set_speed(struct device* dev, speed_t speed)
+{
+    struct serial_dev* sdev = serial_device(dev);
+    lock_sdev(sdev);
+
+    sdev_execmd(sdev, SERIO_SETBRDIV, speed);
+
+    unlock_sdev(sdev);
+}
+
+static void
+__serial_set_cntrl_mode(struct device* dev, tcflag_t cflag)
+{
+    struct serial_dev* sdev = serial_device(dev);
+    lock_sdev(sdev);
+
+    sdev_execmd(sdev, SERIO_SETCNTRLMODE, cflag);
+
+    unlock_sdev(sdev);
+}
+
 #define RXBUF_SIZE 512
 
 struct serial_dev*
@@ -215,18 +248,25 @@ serial_create(struct devclass* class, char* if_ident)
     dev->ops.write_page = __serial_write_page;
     dev->ops.exec_cmd = __serial_exec_command;
     dev->ops.poll = __serial_poll_event;
-
+    
     sdev->dev = dev;
     dev->underlay = sdev;
 
+    struct termport_capability* tp_cap = 
+        new_capability(TERMPORT_CAP, struct termport_capability);
+    tp_cap->set_speed = __serial_set_speed;
+    tp_cap->set_cntrl_mode = __serial_set_cntrl_mode;
+
     waitq_init(&sdev->wq_rxdone);
     waitq_init(&sdev->wq_txdone);
     rbuffer_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE);
     llist_append(&serial_devs, &sdev->sdev_list);
+    
+    device_grant_capability(dev, cap_meta(tp_cap));
 
-    register_device(dev, class, "port%s%d", if_ident, class->variant);
+    register_device(dev, class, "serial%d", class->variant);
 
-    sdev->at_term = term_create(dev, if_ident);
+    term_create(dev, if_ident);
 
     class->variant++;
     return sdev;
index 1b903a735374776c8ab468ff31388a0408bdd3fc..ccee4151853e5138e336626bc87ea0d1bba20a34 100644 (file)
 #define UART_rIE_ELSI (1 << 2)
 #define UART_rIE_EDSSI (1 << 3)
 
+#define UART_rLC_STOPB (1 << 2)
+#define UART_rLC_PAREN (1 << 3)
+#define UART_rLC_PAREVN (1 << 4)
+#define UART_rLC_SETBRK (1 << 6)
+
 #define UART_rLS_THRE (1 << 5)
 #define UART_rLS_DR 1
 #define UART_rLS_BI (1 << 4)
@@ -65,6 +70,7 @@ struct uart16550
         u8_t rie;
         u8_t rfc;
         u8_t rmc;
+        u8_t rlc;
     } cntl_save;
 
     u32_t (*read_reg)(struct uart16550* uart, ptr_t regoff);
@@ -90,7 +96,13 @@ uart_clrie(struct uart16550* uart)
 static inline void
 uart_setie(struct uart16550* uart)
 {
-    uart->write_reg(uart, UART_rIE, uart->cntl_save.rie | 1);
+    uart->write_reg(uart, UART_rIE, uart->cntl_save.rie);
+}
+
+static inline void
+uart_setlc(struct uart16550* uart)
+{
+    uart->write_reg(uart, UART_rLC, uart->cntl_save.rlc);
 }
 
 struct uart16550*
index 8ec752e3349816e730059b7623f253d01602c943..d78f3cf0ff369a3db11edc89ea8ca7ab690f1fa2 100644 (file)
@@ -2,6 +2,7 @@
 #include <lunaix/status.h>
 
 #include <usr/lunaix/serial.h>
+#include <usr/lunaix/term.h>
 
 #include "16550.h"
 
@@ -41,6 +42,22 @@ uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len)
     return RXTX_DONE;
 }
 
+static void
+uart_set_control_mode(struct uart16550* uart, tcflag_t cflags)
+{
+    uart->cntl_save.rie &= ~(UART_rIE_ERBFI | UART_rIE_EDSSI);
+    uart->cntl_save.rie |= (!(cflags & _CLOCAL)) * UART_rIE_EDSSI;
+    uart->cntl_save.rie |= (!!(cflags & _CREAD)) * UART_rIE_ERBFI;
+    uart_setie(uart);
+
+    uart->cntl_save.rlc &= ~(UART_rLC_STOPB | UART_rLC_PAREN | UART_rLC_PAREVN | 0b11);
+    uart->cntl_save.rlc |= (!!(cflags & _CSTOPB)) * UART_rLC_STOPB;
+    uart->cntl_save.rlc |= (!!(cflags & _CPARENB)) * UART_rLC_PAREN;
+    uart->cntl_save.rlc |= (!(cflags & _CPARODD)) * UART_rLC_PAREVN;
+    uart->cntl_save.rlc |= (cflags & _CSZ_MASK) >> 2;
+    uart_setlc(uart);
+}
+
 int
 uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
 {
@@ -52,6 +69,12 @@ uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
         case SERIO_RXDA:
             uart_clrie(uart);
             break;
+        case SERIO_SETBRDIV:
+            // TODO
+            break;
+        case SERIO_SETCNTRLMODE:
+            uart_set_control_mode(uart, va_arg(args, tcflag_t));
+            break;
         default:
             return ENOTSUP;
     }
@@ -92,6 +115,6 @@ done:
 
     serial_accept_buffer(pos->sdev, tmpbuf, i);
     serial_accept_one(pos->sdev, 0);
-    
+
     serial_end_recv(pos->sdev);
 }
index 44103585c7729d8dda8e7e04ab5f1124b9632e87..7d9b57ba5381970a7f991213902ea56f85ed956f 100644 (file)
@@ -34,8 +34,12 @@ setup_default_tty()
 
     assert(device_addalias(NULL, dev_meta(dev), "tty"));
     
-    // TODO implement capability list
-    // for now, we just assume the parameter always pointed to valid device
+    if (!device_get_capability(dev, TERMIOS_CAP)) {
+        FATAL("not a terminal device: %s", console_dev);
+    }
+
+    INFO("system console: %s", console_dev);
+
     sysconsole = dev;
 }
 lunaix_initfn(setup_default_tty, call_on_boot);
\ No newline at end of file
index fdaf244275811feb83a4e5b876cefa199b72602f..08023183ecab1f637d704e7d66e09a62662367c2 100644 (file)
@@ -80,17 +80,17 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
             }
         }
 
+        if (out) {
+            goto do_out;
+        }
+
         if (c == '\n') {
             latest_eol = cooked->ptr + 1;
-            if (!out && (_lf & _ECHONL)) {
+            if ((_lf & _ECHONL)) {
                 rbuffer_put(output, c);
             }
         }
 
-        if (out) {
-            goto do_out;
-        }
-
         // For input procesing
 
         if (c == '\n' || c == EOL) {
@@ -107,7 +107,8 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
         } else if (c == SUSP) {
             raise_sig(tdev, lbuf, SIGSTOP);
         } else if (c == ERASE) {
-            rbuffer_erase(cooked);
+            if (!rbuffer_erase(cooked))
+                continue;
         } else if (c == KILL) {
             // TODO shrink the rbuffer
         } else {
@@ -146,7 +147,7 @@ lcntl_transform_seq(struct term* tdev, struct linebuffer* lbuf, bool out)
         }
     }
 
-    if (!rbuffer_empty(output) && !(_lf & _NOFLSH)) {
+    if (!out && !rbuffer_empty(output) && !(_lf & _NOFLSH)) {
         term_flush(tdev);
     }
 
index 160b62981a7a5b10cda1eb8f4169f4c64dce719e..3cc9741cce9ca47e00bb40801d7283c6580185a4 100644 (file)
@@ -76,27 +76,36 @@ term_exec_cmd(struct device* dev, u32_t req, va_list args)
             break;
         }
         case TDEV_TCGETATTR: {
-            struct _termios* tios = va_arg(args, struct _termios*);
-            *tios = (struct _termios){.c_oflag = term->oflags,
+            struct termios* tios = va_arg(args, struct termios*);
+            *tios = (struct termios){.c_oflag = term->oflags,
                                       .c_iflag = term->iflags,
-                                      .c_lflag = term->lflags};
+                                      .c_lflag = term->lflags,
+                                      .c_cflag = term->cflags};
             memcpy(tios->c_cc, term->cc, _NCCS * sizeof(cc_t));
             tios->c_baud = term->iospeed;
         } break;
         case TDEV_TCSETATTR: {
-            struct _termios* tios = va_arg(args, struct _termios*);
+            struct termios* tios = va_arg(args, struct termios*);
             term->iflags = tios->c_iflag;
             term->oflags = tios->c_oflag;
             term->lflags = tios->c_lflag;
             memcpy(term->cc, tios->c_cc, _NCCS * sizeof(cc_t));
 
+            tcflag_t old_cf = term->cflags;
+            term->cflags = tios->c_cflag;
+
+            if (!term->tp_cap) {
+                goto done;
+            }
+
             if (tios->c_baud != term->iospeed) {
                 term->iospeed = tios->c_baud;
-                if (!term->chdev_ops.set_speed) {
-                    goto done;
-                }
 
-                term->chdev_ops.set_speed(term->chdev, tios->c_baud);
+                term->tp_cap->set_speed(term->chdev, tios->c_baud);
+            }
+
+            if (old_cf != tios->c_cflag) {
+                term->tp_cap->set_cntrl_mode(term->chdev, tios->c_cflag);
             }
         } break;
         default:
@@ -110,14 +119,14 @@ done:
 }
 
 static int
-tdev_do_write(struct device* dev, void* buf, size_t offset, size_t len)
+tdev_do_write(struct device* dev, void* buf, off_t fpos, size_t len)
 {
     struct term* tdev = termdev(dev);
     lbuf_ref_t current = ref_current(&tdev->line_out);
     size_t wrsz = 0;
     while (wrsz < len) {
         wrsz += rbuffer_puts(
-            deref(current), &((char*)buf)[offset + wrsz], len - wrsz);
+            deref(current), &((char*)buf)[wrsz], len - wrsz);
 
         if (rbuffer_full(deref(current))) {
             term_flush(tdev);
@@ -131,7 +140,7 @@ tdev_do_write(struct device* dev, void* buf, size_t offset, size_t len)
 }
 
 static int
-tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
+tdev_do_read(struct device* dev, void* buf, off_t fpos, size_t len)
 {
     struct term* tdev = termdev(dev);
     lbuf_ref_t current = ref_current(&tdev->line_in);
@@ -144,7 +153,7 @@ tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
         }
 
         rdsz += rbuffer_gets(
-            deref(current), &((char*)buf)[offset + rdsz], len - rdsz);
+            deref(current), &((char*)buf)[rdsz], len - rdsz);
     }
 
     return rdsz;
@@ -175,6 +184,7 @@ term_create(struct device* chardev, char* suffix)
 
     terminal->dev->ops.read = tdev_do_read;
     terminal->dev->ops.write = tdev_do_write;
+    terminal->dev->ops.exec_cmd = term_exec_cmd;
 
     // TODO choice of lcntl can be flexible
     terminal->lcntl = line_controls[ANSI_LCNTL];
@@ -189,6 +199,14 @@ term_create(struct device* chardev, char* suffix)
         register_device(terminal->dev, &termdev, "tty%d", termdev.variant++);
     }
 
+    struct capability_meta* termport_cap = device_get_capability(chardev, TERMPORT_CAP);
+    if (termport_cap) {
+        terminal->tp_cap = get_capability(termport_cap, struct termport_capability);
+    }
+
+    struct capability_meta* term_cap = new_capability_marker(TERMIOS_CAP);
+    device_grant_capability(terminal->dev, term_cap);
+
     load_default_setting(terminal);
 
     return terminal;
index 8042e3b2eae71859816926bcbf8d420c2f873001..835659dec048a70c61a2b14a8043e581e31c635c 100644 (file)
@@ -33,7 +33,7 @@ do_read_raw(struct term* tdev)
         max_lb_sz -= sz;
 
         // TODO pass a flags to read to indicate it is non blocking ops
-        sz += chdev->ops.read_async(chdev, inbuffer, sz, max_lb_sz);
+        sz += chdev->ops.read_async(chdev, &inbuffer[sz], 0, max_lb_sz);
     }
 
     rbuffer_puts(line_in->next, inbuffer, sz);
@@ -99,14 +99,14 @@ term_flush(struct term* tdev)
 
     struct linebuffer* line_out = &tdev->line_out;
     size_t xmit_len = line_out->current->len;
-    void* xmit_buf = line_out->next->buffer;
+    char* xmit_buf = line_out->next->buffer;
 
     rbuffer_gets(line_out->current, xmit_buf, xmit_len);
 
     off_t off = 0;
     int ret = 0;
     while (xmit_len && ret >= 0) {
-        ret = tdev->chdev->ops.write(tdev->chdev, xmit_buf, off, xmit_len);
+        ret = tdev->chdev->ops.write(tdev->chdev, &xmit_buf[off], 0, xmit_len);
         xmit_len -= ret;
         off += ret;
     }
index c346c51cc2068fd2e0ea716b562d266847263b33..f65fd08aa74483dcb8422990da737f6d3a20b53a 100644 (file)
@@ -7,7 +7,7 @@
 #include <lunaix/ds/waitq.h>
 #include <lunaix/ds/rbuffer.h>
 
-#include <hal/term.h>
+#include <usr/lunaix/serial.h>
 
 #define SERIAL_RW_RX 0x0
 #define SERIAL_RW_TX 0x1
@@ -28,7 +28,6 @@ struct serial_dev
     struct device* dev;
     struct waitq wq_rxdone;
     struct waitq wq_txdone;
-    struct term* at_term;
     void* backend;
 
     struct rbuffer rxbuf;
index 6b76db3b75e3c56ea48772c1578b1fbaad1699c8..0f11e525bac5ce73e15684fd55e9b4e06b609de9 100644 (file)
@@ -31,6 +31,29 @@ struct term_lcntl
     int (*process_and_put)(struct term*, struct linebuffer*, char);
 };
 
+/**
+ * @brief Communication port capability that a device is supported natively, 
+ *          or able to emulate low level serial transmission behaviour specify 
+ *          by POSIX1-2008, section 11.
+ * 
+ */
+#define TERMPORT_CAP 0x4d524554U
+
+/**
+ * @brief A termios capability that a device provide interfaces which is 
+ *          compliant to POSIX1-2008
+ * 
+ */
+#define TERMIOS_CAP 0x534f4954U
+
+struct termport_capability
+{
+    CAPABILITY_META;
+
+    void (*set_speed)(struct device*, speed_t);
+    void (*set_cntrl_mode)(struct device*, tcflag_t);
+};
+
 struct term
 {
     struct device* dev;
@@ -40,15 +63,13 @@ struct term
     struct linebuffer line_in;
     pid_t fggrp;
 
-    struct
-    {
-        int (*set_speed)(struct device*, speed_t);
-    } chdev_ops;
+    struct termport_capability* tp_cap;
 
     /* -- POSIX.1-2008 compliant fields -- */
     tcflag_t iflags;
     tcflag_t oflags;
     tcflag_t lflags;
+    tcflag_t cflags;
     cc_t cc[_NCCS];
     speed_t iospeed;
 };
index 05b8639a6579c790582a4bf379ea206a72b7a3ab..287cdadc6612db45ac35b0ae06fc2fa01dba4740 100644 (file)
 #define DEV_IFSEQ 0x1 // sequential (character) device
 #define DEV_IFSYS 0x3 // a system device
 
+struct capability_meta
+{
+    struct llist_header caps;
+    unsigned int cap_type;
+};
+
+#define CAPABILITY_META                     \
+    union {                                 \
+        struct capability_meta cap_meta;    \
+        struct {                            \
+            struct llist_header caps;       \
+            unsigned int cap_type;          \
+        };                                  \
+    }
+
+#define get_capability(cap, cap_type)       \
+    container_of((cap), cap_type, cap_meta)
+#define cap_meta(cap) (&(cap)->cap_meta)
+
+typedef struct llist_header capability_list_t;
+
+
 struct device_meta
 {
     u32_t magic;
@@ -149,6 +171,8 @@ struct device
 
     DEVICE_METADATA;
 
+    capability_list_t capabilities;
+
     /* -- device state -- */
 
     mutex_t lock;
@@ -324,6 +348,22 @@ device_populate_info(struct device* dev, struct dev_info* devinfo);
 void
 device_scan_drivers();
 
+/*------ Capability ------*/
+
+struct capability_meta*
+alloc_capability(int cap, unsigned int size);
+
+#define new_capability(cap_type, cap_impl)\
+    ((cap_impl*)alloc_capability((cap_type), sizeof(cap_impl)))
+
+#define new_capability_marker(cap_type)\
+    (alloc_capability((cap_type), sizeof(struct capability_meta)))
+
+void
+device_grant_capability(struct device* dev, struct capability_meta* cap);
+
+struct capability_meta*
+device_get_capability(struct device* dev, unsigned int cap_type);
 /*------ Load hooks ------*/
 
 void
index b372daad4ce64f18b7665fb1180bc644127ab1cc..487785762d1aa8542adf0a2effcc92dc790798e7 100644 (file)
@@ -29,6 +29,7 @@
     }
 
 #define DEBUG(fmt, ...) kprintf(KDEBUG fmt, ##__VA_ARGS__)
+#define INFO(fmt, ...) kprintf(KINFO fmt, ##__VA_ARGS__)
 #define WARN(fmt, ...) kprintf(KWARN fmt, ##__VA_ARGS__)
 #define ERROR(fmt, ...) kprintf(KERROR fmt, ##__VA_ARGS__)
 #define FATAL(fmt, ...)                                                        \
index 779235519d0ce6263ce1f72250bcb0164d3db8f5..9142a4dc440d8ea802fa9ee65ea967ba73fbe412 100644 (file)
@@ -6,7 +6,7 @@
 #define DT_FILE 0x0
 #define DT_DIR 0x1
 #define DT_SYMLINK 0x2
-#define DT_PIPE 0x2
+#define DT_PIPE 0x3
 
 struct lx_dirent
 {
index 7cdd74b0a264752275d1ca8ce343bb06837618da..c01bb15106fe88b2e673204e8f99fd691c3d3e1d 100644 (file)
@@ -9,4 +9,7 @@
 #define SERIO_TXEN IOREQ(3, 0)
 #define SERIO_TXDA IOREQ(4, 0)
 
+#define SERIO_SETBRDIV IOREQ(5, 0)
+#define SERIO_SETCNTRLMODE IOREQ(6, 0)
+
 #endif /* __LUNAIX_USERIAL_H */
index 8866b308971a38adbe8a25b44d16ce27ac3c46af..b1f6c1fff37eef5ec71d9c84b30123eeb94edc59 100644 (file)
 #define _B19200 19200
 #define _B38400 38400
 
+#define _CLOCAL 1
+#define _CREAD (1 << 1)
+#define _CSZ_MASK (0b11 << 2)
+#define _CS5 (0b00 << 2)
+#define _CS6 (0b01 << 2)
+#define _CS7 (0b10 << 2)
+#define _CS8 (0b11 << 2)
+#define _CSTOPB (1 << 4)
+#define _CHUPCL (1 << 5)
+#define _CPARENB (1 << 6)
+#define _CPARODD (1 << 7)
+
 #define _TCSANOW 1
 #define _TCSADRAIN 2
 #define _TCSAFLUSH 3
@@ -82,7 +94,7 @@ typedef int tcflag_t;
 typedef char cc_t;
 typedef unsigned int speed_t;
 
-struct _termios
+struct termios
 {
     tcflag_t c_iflag;
     tcflag_t c_oflag;
diff --git a/lunaix-os/kernel/device/capability.c b/lunaix-os/kernel/device/capability.c
new file mode 100644 (file)
index 0000000..b31f914
--- /dev/null
@@ -0,0 +1,32 @@
+#include <lunaix/device.h>
+#include <lunaix/mm/valloc.h>
+
+struct capability_meta*
+alloc_capability(int cap, unsigned int size) 
+{
+    struct capability_meta* cm = (struct capability_meta*)vzalloc(size);
+
+    cm->cap_type = cap;
+
+    return cm;
+}
+
+void
+device_grant_capability(struct device* dev, struct capability_meta* cap)
+{
+    llist_append(&dev->capabilities, &cap->caps);
+}
+
+struct capability_meta*
+device_get_capability(struct device* dev, unsigned int cap_type)
+{
+    struct capability_meta *pos, *n;
+
+    llist_for_each(pos, n, &dev->capabilities, caps) {
+        if (pos->cap_type == cap_type){
+            return pos;
+        }
+    }
+
+    return NULL;
+}
\ No newline at end of file
index b88f8f6c283ea311fb3e524059f67a6eabe3d143..d3552c66d539f119b085697ad0d2840c36939cae 100644 (file)
@@ -77,6 +77,7 @@ device_create(struct device* dev,
     dev->dev_type = type;
 
     device_init_meta(dev_meta(dev), parent, DEV_STRUCT);
+    llist_init_head(&dev->capabilities);
     mutex_init(&dev->lock);
     iopoll_init_evt_q(&dev->pollers);
 }
@@ -299,9 +300,9 @@ __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
         goto done;
     }
 
-    struct device* dev = (struct device*)fd_s->file->inode->data;
-    if (valid_device_subtype_ref(dev, DEV_STRUCT)) {
-        errno &= ENODEV;
+    struct device* dev = resolve_device(fd_s->file->inode->data);
+    if (!valid_device_subtype_ref(dev, DEV_STRUCT)) {
+        errno = ENODEV;
         goto done;
     }
 
@@ -312,11 +313,11 @@ __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
     }
 
     if (!dev->ops.exec_cmd) {
-        errno &= ENOTSUP;
+        errno = ENOTSUP;
         goto done;
     }
 
-    errno &= dev->ops.exec_cmd(dev, req, args);
+    errno = dev->ops.exec_cmd(dev, req, args);
 
 done:
     return DO_STATUS_OR_RETURN(errno);
index bfcc3a5cd7334c2904e3bfc0c21614a46a64150a..ab4dea50549c4c359f03a5c03e008a518377ef26 100644 (file)
@@ -63,7 +63,7 @@ rbuffer_puts(struct rbuffer* rb, char* buf, size_t len)
 int
 rbuffer_gets(struct rbuffer* rb, char* buf, size_t len)
 {
-    if (!len)
+    if (!len || !rb->len)
         return 0;
 
     size_t nlen = MIN(len, rb->len);
index 96cc7418cec8a702573120a70b824d79fcaf89ac..2b996d413c8b304dfb6e7efc71454ddbd9a8c226 100644 (file)
@@ -63,6 +63,8 @@ __vfs_do_unmount(struct v_mount* mnt)
 
     mnt_chillax(mnt->parent);
 
+    mnt->mnt_point->mnt = mnt->parent;
+
     vfs_sb_free(sb);
     atomic_fetch_sub(&mnt->mnt_point->ref_count, 1);
     vfree(mnt);
@@ -249,6 +251,11 @@ __DEFINE_LXSYSCALL4(int,
         goto done;
     }
 
+    if (mnt->mnt->mnt_point == mnt) {
+        errno = EBUSY;
+        goto done;
+    }
+
     // By our convention.
     // XXX could we do better?
     struct device* device = NULL;
index 80d2036b88ab8657e48fa45ab96ab566d3b7f256..28cede5e5a2ad44e2dc90487acb3dad79c98e93e 100644 (file)
@@ -708,7 +708,7 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
     file->inode->atime = clock_unixtime();
 
     if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
-        errno = file->ops->read(file->inode, buf, count, file->f_pos);
+    errno = file->ops->read(file->inode, buf, count, file->f_pos);
     } else {
         errno = pcache_read(file->inode, buf, count, file->f_pos);
     }
@@ -860,7 +860,7 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
 int
 vfs_get_dtype(int itype)
 {
-    if ((itype & VFS_IFSYMLINK)) {
+    if ((itype & VFS_IFSYMLINK) == VFS_IFSYMLINK) {
         return DT_SYMLINK;
     } else if (!(itype & VFS_IFFILE)) {
         return DT_DIR;
@@ -1003,6 +1003,11 @@ __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
         goto done;
     }
 
+    if (!(errno = vfs_walk(parent, name_value, &dir, NULL, 0))) {
+        errno = EEXIST;
+        goto done;
+    }
+
     if ((errno = vfs_check_writable(parent))) {
         goto done;
     }
index cf2d43c4e15d195b428fa97e7cedc859e882e0ec..2540077437f6befe919880b4ee5126984a073271 100644 (file)
@@ -23,6 +23,8 @@
 #include <lunaix/tty/console.h>
 #include <lunaix/tty/tty.h>
 
+#include <hal/term.h>
+
 static struct console lx_console;
 
 int
@@ -38,24 +40,16 @@ void
 console_flush();
 
 static waitq_t lx_reader;
-static volatile char ttychr;
 
 static volatile pid_t fg_pgid = 0;
 
-static inline void
-print_control_code(const char cntrl)
-{
-    console_write_char('^');
-    console_write_char(cntrl + 64);
-}
-
 int
 __lxconsole_listener(struct input_device* dev)
 {
     u32_t key = dev->current_pkt.sys_code;
     u32_t type = dev->current_pkt.pkt_type;
     kbd_kstate_t state = key >> 16;
-    ttychr = key & 0xff;
+    u8_t ttychr = key & 0xff;
     key = key & 0xffff;
 
     if (type == PKT_RELEASE) {
@@ -68,18 +62,6 @@ __lxconsole_listener(struct input_device* dev)
             goto done;
         }
         ttychr = cntrl - 'a' + 1;
-        switch (ttychr) {
-            case TCINTR:
-                signal_send(-fg_pgid, _SIGINT);
-                print_control_code(ttychr);
-                break;
-            case TCSTOP:
-                signal_send(-fg_pgid, _SIGSTOP);
-                print_control_code(ttychr);
-                break;
-            default:
-                break;
-        }
     } else if (key == KEY_PG_UP) {
         console_view_up();
         goto done;
@@ -92,6 +74,7 @@ __lxconsole_listener(struct input_device* dev)
         goto done;
     }
 
+    fifo_putone(&lx_console.input, ttychr);
     pwake_all(&lx_reader);
 
 done:
@@ -161,40 +144,11 @@ __tty_read(struct device* dev, void* buf, size_t offset, size_t len)
     struct console* console = (struct console*)dev->underlay;
 
     size_t count = fifo_read(&console->input, buf, len);
-    if (count > 0 && ((char*)buf)[count - 1] == '\n') {
+    if (count > 0) {
         return count;
     }
 
-    while (count < len) {
-        pwait(&lx_reader);
-
-        if (ttychr < 0x1B) {
-            // ASCII control codes
-            switch (ttychr) {
-                case TCINTR:
-                    fifo_clear(&console->input);
-                    return 0;
-                case TCBS:
-                    if (fifo_backone(&console->input)) {
-                        console_write_char(ttychr);
-                    }
-                    continue;
-                case TCLF:
-                case TCCR:
-                    goto proceed;
-                default:
-                    break;
-            }
-            print_control_code(ttychr);
-            continue;
-        }
-
-    proceed:
-        console_write_char(ttychr);
-        if (!fifo_putone(&console->input, ttychr) || ttychr == '\n') {
-            break;
-        }
-    }
+    pwait(&lx_reader);
 
     return count + fifo_read(&console->input, buf + count, len - count);
 }
@@ -355,12 +309,14 @@ lxconsole_spawn_ttydev(struct device_def* devdef)
 
     register_device(tty_dev, &devdef->class, "vcon");
 
+    term_create(tty_dev, "FB");
+
     return 0;
 }
 
 static struct device_def lxconsole_def = {
     .name = "Lunaix Virtual Console",
-    .class = DEVCLASSV(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN, 12),
+    .class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN),
     .init = lxconsole_spawn_ttydev
 };
 // FIXME
index 4e0ea8662dc7bf4b35d71a6df59e5d922e5f230f..c332bf7d361e594f0671ae1dba68647df03d83bd 100644 (file)
@@ -10,6 +10,8 @@ export ARCH
 
 DEPS := $(CC) $(LD) $(AR) xorriso grub-mkrescue
 
+CMDLINE ?= console=/dev/ttyFB0
+
 kbuild_dir := build
 kbin_dir := $(kbuild_dir)/bin
 os_img_dir := $(kbuild_dir)/img
@@ -45,9 +47,11 @@ kernel:
        @$(MAKE) $(MKFLAGS) -I $(mkinc_dir) -f kernel.mk all
 
 .PHONY: image
+export KCMD=$(CMDLINE)
+export _OS_NAME=$(OS_NAME)
 image: usr/build kernel
        $(call status,TASK,$(notdir $@))
-       @./config-grub.sh ${OS_NAME} $(os_img_dir)/boot/grub/grub.cfg
+       @./config-grub.sh $(os_img_dir)/boot/grub/grub.cfg
        @cp -r usr/build/* $(os_img_dir)/usr
        @cp -r $(kbin_dir)/* $(os_img_dir)/boot
        @grub-mkrescue -o $(kimg) $(os_img_dir) -- -volid "$(OS_ID) $(OS_VER)" -system_id "$(OS_NAME)"
@@ -92,7 +96,6 @@ debug-qemu: all-debug
        @QMPORT=$(QEMU_MON_PORT) gdb $(kbin) -ex "target remote localhost:1234"
 
 debug-qemu-vscode: all-debug
-       @i686-elf-objcopy --only-keep-debug $(kbin) $(kbuild_dir)/kernel.dbg
        @qemu-system-i386 $(call get_qemu_options,$(kimg))
        @sleep 0.5
        @telnet 127.0.0.1 $(QEMU_MON_PORT)
index 0a15f8cdc2fa1bd851b33523dfef7e79c189ca02..9f0d35b54b9ed463a9bce190304812b0733d0e62 100644 (file)
@@ -11,14 +11,26 @@ int
 main(int argc, const char* argv[])
 {
     int fd = 0;
-    unsigned int size = 0;
+    int size = 0;
+    struct file_stat stat;
     for (int i = 1; i < argc; i++) {
         fd = open(argv[i], FO_RDONLY);
+                
         if (fd < 0) {
             printf("open failed: %s (error: %d)", argv[i], fd);
             continue;
         }
 
+        if (fstat(fd, &stat) < 0) {
+            printf("fail to get stat %d\n", errno);
+            return 1;
+        }
+
+        if (!(stat.mode & F_MFILE)) {
+            printf("%s is a directory", argv[i]);
+            return 1;
+        }
+
         do {
             size = read(fd, buffer, BUFSIZE);
             write(stdout, buffer, size);
index 1b80f495d05770b7dca832831a5b625f6f8733d5..0a2f5418a9de84eca57dcd9af649b7360ed167c7 100644 (file)
@@ -2,6 +2,7 @@
 #include <fcntl.h>
 #include <lunaix/lunaix.h>
 #include <lunaix/mount.h>
+#include <termios.h>
 #include <stdio.h>
 #include <unistd.h>
 
         }                                                                      \
     } while (0)
 
+#define check(statement)                                      \
+    do {                                                                       \
+        int err = 0;                                                           \
+        if ((err = (statement))) {                            \
+            syslog(2, #statement " failed: %d", err);   \
+            return err;                                                        \
+        }                                                                      \
+    } while (0)
+
+int
+init_termios(int fd) {
+    struct termios term;
+
+    check(tcgetattr(fd, &term));
+
+    term.c_lflag = ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHONL;
+    term.c_iflag = ICRNL | IGNBRK;
+    term.c_oflag = ONLCR | OPOST;
+    term.c_cflag = CREAD | CLOCAL | CS8 | CPARENB;
+    term.c_cc[VERASE] = 0x08;
+
+    check(tcsetattr(fd, 0, &term));
+
+    return 0;
+}
+
 int
 main(int argc, const char** argv)
 {
@@ -32,6 +59,8 @@ main(int argc, const char** argv)
         return err;
     }
 
+    check(init_termios(err));
+
     if ((err = dup(err)) < 0) {
         syslog(2, "fail to setup tty i/o (%d)\n", errno);
         return err;
diff --git a/lunaix-os/usr/libc/includes/termios.h b/lunaix-os/usr/libc/includes/termios.h
new file mode 100644 (file)
index 0000000..42ad0ac
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef __LUNAIX_TERMIOS_H
+#define __LUNAIX_TERMIOS_H
+
+#include <lunaix/term.h>
+
+#define BRKINT _BRKINT
+#define ICRNL _ICRNL
+#define IGNBRK _IGNBRK
+#define IGNCR _IGNCR
+#define IGNPAR _IGNPAR
+#define INLCR _INLCR
+#define INPCK _INPCK
+#define ISTRIP _ISTRIP
+#define IUCLC _IUCLC
+#define IXANY _IXANY
+#define IXOFF _IXOFF
+#define IXON _IXON
+#define PARMRK _PARMRK
+
+#define OPOST _OPOST
+#define OCRNL _OCRNL
+
+// 2
+// 3
+// 4
+
+#define ONLRET _ONLRET
+#define ONLCR _ONLCR
+
+// 7
+
+#define OLCUC _OLCUC
+
+#define ECHO _ECHO
+#define ECHOE _ECHOE
+#define ECHOK _ECHOK
+#define ECHONL _ECHONL
+#define ICANON _ICANON
+#define ISIG _ISIG
+#define IEXTEN _IEXTEN
+#define NOFLSH _NOFLSH
+
+#define VEOF _VEOF
+#define VEOL _VEOL
+#define VERASE _VERASE
+#define VINTR _VINTR
+#define VKILL _VKILL
+#define VQUIT _VQUIT
+#define VSUSP _VSUSP
+#define VSTART _VSTART
+#define VSTOP _VSTOP
+#define VMIN _VMIN
+#define VTIME _VTIME
+#define NCCS _NCCS
+
+#define B50 _B50
+#define B75 _B75
+#define B110 _B110
+#define B134 _B134
+#define B150 _B150
+#define B200 _B200
+#define B300 _B300
+#define B600 _B600
+#define B1200 _B1200
+#define B1800 _B1800
+#define B2400 _B2400
+#define B4800 _B4800
+#define B9600 _B9600
+#define B19200 _B19200
+#define B38400 _B38400
+
+#define CLOCAL _CLOCAL
+#define CREAD _CREAD
+#define CS5 _CS5
+#define CS6 _CS6
+#define CS7 _CS7
+#define CS8 _CS8
+#define CSTOPB _CSTOPB
+#define CHUPCL _CHUPCL
+#define CPARENB _CPARENB
+#define CPARODD _CPARODD
+
+#define TCSANOW _TCSANOW
+#define TCSADRAIN _TCSADRAIN
+#define TCSAFLUSH _TCSAFLUSH
+
+static inline speed_t cfgetispeed(const struct termios* termios) { return termios->c_baud; }
+static inline speed_t cfgetospeed(const struct termios* termios) { return termios->c_baud; }
+
+static inline int cfsetispeed(struct termios* termios, speed_t baud)
+{
+    termios->c_baud = baud;
+    return 0;
+}
+
+static inline int cfsetospeed(struct termios* termios, speed_t baud)
+{
+    termios->c_baud = baud;
+    return 0;
+}
+
+
+// TODO
+//int     tcdrain(int);
+//int     tcflow(int, int);
+//int     tcflush(int, int);
+// pid_t   tcgetsid(int);
+
+int     tcgetattr(int, struct termios *);
+int     tcsendbreak(int, int);
+int     tcsetattr(int, int, const struct termios *);
+
+
+#endif /* __LUNAIX_TERMIOS_H */
diff --git a/lunaix-os/usr/libc/src/termios.c b/lunaix-os/usr/libc/src/termios.c
new file mode 100644 (file)
index 0000000..52c97e4
--- /dev/null
@@ -0,0 +1,22 @@
+#include <termios.h>
+#include <lunaix/ioctl.h>
+
+int
+tcgetattr(int fd, struct termios* termios_p) 
+{
+    return ioctl(fd, TDEV_TCGETATTR, termios_p);
+}
+
+
+int
+tcsendbreak(int fd, int ) 
+{
+    // TODO
+    return 0;
+}
+
+int
+tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
+{
+    return ioctl(fd, TDEV_TCSETATTR, termios_p);
+}
index 646dd6bddb219ba53d2205132070f6d0eba797de..ece96e4a9947fef95f83188dccba73705da9a4f4 100644 (file)
@@ -20,9 +20,9 @@ main(int argc, const char* argv[])
 
     while ((dent = readdir(dir))) {
         if (dent->d_type == DT_DIR) {
-            printf(" \033[3m%s\033[39;49m\n", dent->d_name);
+            printf(" %s\n", dent->d_name);
         } else if (dent->d_type == DT_SYMLINK) {
-            printf(" \033[13m%s@\033[39;49m\n", dent->d_name);
+            printf(" %s@\n", dent->d_name);
         } else {
             printf(" %s\n", dent->d_name);
         }
index 4a924db7a9130f49f7e8ee80e645389a17054470..2c9bb8d1ec7fa2f5bb93198ab37e4280ff98ba35 100644 (file)
@@ -143,7 +143,7 @@ sh_loop()
 
     while (1) {
         getcwd(pwd, 512);
-        printf("[\033[2m%s\033[39;49m]$ ", pwd);
+        printf("[%s]$ ", pwd);
         int sz = read(stdin, buf, 511);
 
         if (sz < 0) {