Browse Source

添加tty驱动框架,去除lwp下面的pty和console

linzhenxing 3 years ago
parent
commit
00f2a3afa3

+ 4 - 11
bsp/qemu-vexpress-a9/.config

@@ -45,7 +45,7 @@ CONFIG_RT_USING_MUTEX=y
 CONFIG_RT_USING_EVENT=y
 CONFIG_RT_USING_MAILBOX=y
 CONFIG_RT_USING_MESSAGEQUEUE=y
-CONFIG_RT_USING_SIGNALS=y
+# CONFIG_RT_USING_SIGNALS is not set
 
 #
 # Memory Management
@@ -161,6 +161,8 @@ CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
 CONFIG_RT_USING_SERIAL=y
 CONFIG_RT_SERIAL_USING_DMA=y
 CONFIG_RT_SERIAL_RB_BUFSZ=256
+CONFIG_RT_USING_TTY=y
+# CONFIG_RT_TTY_DEBUG is not set
 # CONFIG_RT_USING_CAN is not set
 # CONFIG_RT_USING_HWTIMER is not set
 # CONFIG_RT_USING_CPUTIME is not set
@@ -226,7 +228,6 @@ CONFIG_RT_USING_MUSL=y
 # CONFIG_RT_USING_PTHREADS is not set
 CONFIG_RT_USING_POSIX=y
 CONFIG_RT_USING_POSIX_MMAP=y
-CONFIG_RT_USING_POSIX_TERMIOS=y
 # CONFIG_RT_USING_POSIX_GETLINE is not set
 CONFIG_RT_USING_POSIX_AIO=y
 CONFIG_RT_POSIX_AIO_THREAD_STACK_SIZE=2048
@@ -439,7 +440,6 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_LORA_GW_DRIVER_LIB is not set
 # CONFIG_PKG_USING_LORA_PKT_SNIFFER is not set
 # CONFIG_PKG_USING_HM is not set
-# CONFIG_PKG_USING_SMALL_MODBUS is not set
 
 #
 # security packages
@@ -541,13 +541,6 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_QFPLIB_M0_TINY is not set
 # CONFIG_PKG_USING_QFPLIB_M3 is not set
 
-#
-# CMSIS: ARM Cortex-M Microcontroller Software Interface Standard
-#
-# CONFIG_PKG_USING_CMSIS_5 is not set
-# CONFIG_PKG_USING_CMSIS_5_AUX is not set
-# CONFIG_PKG_USING_CMSIS_RTOS2 is not set
-
 #
 # Micrium: Micrium software products porting for RT-Thread
 #
@@ -566,6 +559,7 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_FLASHDB is not set
 # CONFIG_PKG_USING_SQLITE is not set
 # CONFIG_PKG_USING_RTI is not set
+# CONFIG_PKG_USING_CMSIS is not set
 # CONFIG_PKG_USING_DFS_YAFFS is not set
 # CONFIG_PKG_USING_LITTLEFS is not set
 # CONFIG_PKG_USING_DFS_JFFS2 is not set
@@ -665,7 +659,6 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_MISAKA_RGB_BLING is not set
 # CONFIG_PKG_USING_BL_MCU_SDK is not set
 # CONFIG_PKG_USING_SOFT_SERIAL is not set
-# CONFIG_PKG_USING_MB85RS16 is not set
 
 #
 # AI packages

+ 1 - 5
bsp/qemu-vexpress-a9/rtconfig.h

@@ -30,7 +30,6 @@
 #define RT_USING_EVENT
 #define RT_USING_MAILBOX
 #define RT_USING_MESSAGEQUEUE
-#define RT_USING_SIGNALS
 
 /* Memory Management */
 
@@ -119,6 +118,7 @@
 #define RT_USING_SERIAL
 #define RT_SERIAL_USING_DMA
 #define RT_SERIAL_RB_BUFSZ 256
+#define RT_USING_TTY
 #define RT_USING_I2C
 #define RT_USING_I2C_BITOPS
 #define RT_USING_PIN
@@ -153,7 +153,6 @@
 #define RT_USING_MUSL
 #define RT_USING_POSIX
 #define RT_USING_POSIX_MMAP
-#define RT_USING_POSIX_TERMIOS
 #define RT_USING_POSIX_AIO
 #define RT_POSIX_AIO_THREAD_STACK_SIZE 2048
 #define RT_USING_POSIX_CLOCKTIME
@@ -279,9 +278,6 @@
 /* acceleration: Assembly language or algorithmic acceleration packages */
 
 
-/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
-
-
 /* Micrium: Micrium software products porting for RT-Thread */
 
 

+ 10 - 0
components/drivers/Kconfig

@@ -45,6 +45,16 @@ if RT_USING_SERIAL
 
 endif
 
+config RT_USING_TTY
+    bool "Using TTY SYSTEM"
+    default y
+
+if RT_USING_TTY
+    config RT_TTY_DEBUG
+        bool "Using TTY DEBUG"
+        default n
+endif
+
 config RT_USING_CAN
     bool "Using CAN device drivers"
     default n

+ 1 - 5
components/drivers/serial/serial.c

@@ -38,9 +38,8 @@
 #include <dfs_posix.h>
 #include <dfs_poll.h>
 
-#ifdef RT_USING_POSIX_TERMIOS
 #include <posix_termios.h>
-#endif
+
 
 /* it's possible the 'getc/putc' is defined by stdio.h in gcc/newlib. */
 #ifdef getc
@@ -894,7 +893,6 @@ static rt_size_t rt_serial_write(struct rt_device *dev,
     }
 }
 
-#ifdef RT_USING_POSIX_TERMIOS
 struct speed_baudrate_item
 {
     speed_t speed;
@@ -989,8 +987,6 @@ static void _tc_flush(struct rt_serial_device *serial, int queue)
 
 }
 
-#endif
-
 static rt_err_t rt_serial_control(struct rt_device *dev,
                                   int              cmd,
                                   void             *args)

+ 11 - 0
components/drivers/tty/SConscript

@@ -0,0 +1,11 @@
+from building import *
+
+# The set of source files associated with this SConscript file.
+src = Glob('*.c')
+cwd = GetCurrentDir()
+CPPPATH = [cwd + "/include"]
+
+if GetDepend('RT_USING_LWP'):
+    group = DefineGroup('tty', src, depend = ['RT_USING_TTY'], CPPPATH = CPPPATH)
+
+Return('group')

+ 324 - 0
components/drivers/tty/console.c

@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#include <rtthread.h>
+#include <dfs_file.h>
+#include <dfs_fs.h>
+#include <tty.h>
+
+#define DBG_TAG               "CONSOLE"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL               DBG_LOG
+#else
+#define DBG_LVL               DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+static struct tty_struct console_driver;
+
+static void console_rx_notify(struct rt_device *dev)
+{
+    struct tty_struct *console = NULL;
+    int len = 0;
+    int lens = 0;
+    char ch = 0;
+    char buf[1024] = {0};
+
+    console = (struct tty_struct *)dev;
+    RT_ASSERT(console != RT_NULL);
+
+    while (1)
+    {
+        len = rt_device_read(console->driver, -1, &ch, 1);
+        if (len == 0)
+        {
+            break;
+        }
+        lens += len;
+        buf[lens-1] = ch;
+        if (lens > 1024)
+        {
+            break;
+        }
+    }
+
+    if (console->ldisc->ops->receive_buf)
+    {
+        console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens);
+    }
+}
+
+struct tty_struct *console_tty_get(void)
+{
+    return &console_driver;
+}
+
+static void iodev_close(struct tty_struct *console)
+{
+    struct rt_device_notify rx_notify;
+
+    rx_notify.notify = RT_NULL;
+    rx_notify.dev = RT_NULL;
+
+    /* clear notify */
+    rt_device_control(console->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
+    rt_device_close(console->driver);
+}
+
+static rt_err_t iodev_open(struct tty_struct *console)
+{
+    rt_err_t ret = RT_EOK;
+    struct rt_device_notify rx_notify;
+    rt_uint16_t oflags = 0;
+
+    rt_device_control(console->driver, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
+
+    ret = rt_device_open(console->driver, oflags);
+    if (ret != RT_EOK)
+    {
+        return RT_ERROR;
+    }
+
+    rx_notify.notify = console_rx_notify;
+    rx_notify.dev = (struct rt_device *)console;
+    rt_device_control(console->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
+    return RT_EOK;
+}
+
+struct rt_device *console_get_iodev(void)
+{
+    rt_base_t level = 0;
+    struct rt_device *iodev = RT_NULL;
+
+    level = rt_hw_interrupt_disable();
+    iodev = console_driver.driver;
+    rt_hw_interrupt_enable(level);
+    return iodev;
+}
+
+struct rt_device *console_set_iodev(struct rt_device *iodev)
+{
+    rt_base_t level = 0;
+    struct rt_device *io_before = RT_NULL;
+    struct tty_struct *console = RT_NULL;
+
+    RT_ASSERT(iodev != RT_NULL);
+
+    console = &console_driver;
+
+    level = rt_hw_interrupt_disable();
+
+    RT_ASSERT(console->init_flag >= TTY_INIT_FLAG_REGED);
+
+    io_before = console->driver;
+
+    if (iodev == io_before)
+    {
+        goto exit;
+    }
+
+    if (console->init_flag >= TTY_INIT_FLAG_INITED)
+    {
+        /* close old device */
+        iodev_close(console);
+    }
+
+    console->driver = iodev;
+
+    if (console->init_flag >= TTY_INIT_FLAG_INITED)
+    {
+        rt_err_t ret;
+        /* open new device */
+        ret = iodev_open(console);
+        RT_ASSERT(ret == RT_EOK);
+    }
+
+exit:
+    rt_hw_interrupt_enable(level);
+    return io_before;
+}
+
+/* RT-Thread Device Interface */
+/*
+ * This function initializes console device.
+ */
+static rt_err_t rt_console_init(struct rt_device *dev)
+{
+    rt_base_t level = 0;
+    rt_err_t result = RT_EOK;
+    struct tty_struct *console = RT_NULL;
+
+    RT_ASSERT(dev != RT_NULL);
+
+    console = (struct tty_struct *)dev;
+
+    level = rt_hw_interrupt_disable();
+
+    RT_ASSERT(console->init_flag == TTY_INIT_FLAG_REGED);
+
+    result = iodev_open(console);
+    if (result != RT_EOK)
+    {
+        goto exit;
+    }
+
+    console->init_flag = TTY_INIT_FLAG_INITED;
+exit:
+    rt_hw_interrupt_enable(level);
+    return result;
+}
+
+static rt_err_t rt_console_open(struct rt_device *dev, rt_uint16_t oflag)
+{
+    rt_err_t result = RT_EOK;
+    struct tty_struct *console = RT_NULL;
+
+    RT_ASSERT(dev != RT_NULL);
+    console = (struct tty_struct *)dev;
+    RT_ASSERT(console != RT_NULL);
+    RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+    return result;
+}
+
+static rt_err_t rt_console_close(struct rt_device *dev)
+{
+    rt_err_t result = RT_EOK;
+    struct tty_struct *console = RT_NULL;
+
+    console = (struct tty_struct *)dev;
+    RT_ASSERT(console != RT_NULL);
+    RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+    return result;
+}
+
+static rt_size_t rt_console_read(struct rt_device *dev,
+        rt_off_t          pos,
+        void             *buffer,
+        rt_size_t         size)
+{
+    rt_size_t len = 0;
+    return len;
+}
+
+static rt_size_t rt_console_write(struct rt_device *dev,
+        rt_off_t          pos,
+        const void       *buffer,
+        rt_size_t         size)
+{
+    rt_base_t level = 0;
+    rt_size_t len = 0;
+    struct tty_struct *console = RT_NULL;
+
+    console = (struct tty_struct *)dev;
+    RT_ASSERT(console != RT_NULL);
+    RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+
+    level = rt_hw_interrupt_disable();
+    len = rt_device_write((struct rt_device *)console->driver, -1, buffer, size);
+    rt_hw_interrupt_enable(level);
+
+    return len;
+}
+
+static rt_err_t  rt_console_control(rt_device_t dev, int cmd, void *args)
+{
+    rt_base_t level = 0;
+    rt_size_t len = 0;
+    struct tty_struct *console = RT_NULL;
+
+    console = (struct tty_struct *)dev;
+    RT_ASSERT(console != RT_NULL);
+    RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
+
+    level = rt_hw_interrupt_disable();
+    len = rt_device_control((struct rt_device *)console->driver, cmd, args);
+    rt_hw_interrupt_enable(level);
+
+    return len;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops console_ops =
+{
+    rt_console_init,
+    rt_console_open,
+    rt_console_close,
+    rt_console_read,
+    rt_console_write,
+    rt_console_control,
+};
+#endif
+/*
+ * console register
+ */
+ static struct dfs_file_ops con_fops;
+rt_err_t console_register(const char *name, struct rt_device *iodev)
+{
+    rt_base_t level = 0;
+    rt_err_t ret = RT_EOK;
+    struct rt_device *device = RT_NULL;
+    struct tty_struct *console = &console_driver;
+
+    level = rt_hw_interrupt_disable();
+    RT_ASSERT(console->init_flag == TTY_INIT_FLAG_NONE);
+    RT_ASSERT(iodev != RT_NULL);
+
+    device = &(console->parent);
+
+    device->type        = RT_Device_Class_Char;
+
+#ifdef RT_USING_DEVICE_OPS
+    device->ops         = &console_ops;
+#else
+    device->init        = rt_console_init;
+    device->open        = rt_console_open;
+    device->close       = rt_console_close;
+    device->read        = rt_console_read;
+    device->write       = rt_console_write;
+    device->control     = rt_console_control;
+#endif
+
+
+    /* register a character device */
+    ret = rt_device_register(device, name, 0);
+    if (ret != RT_EOK)
+    {
+        LOG_E("console driver register fail\n");
+        goto exit;
+    }
+
+#ifdef RT_USING_POSIX
+    /* set fops */
+    console_set_fops(&con_fops);
+    device->fops = &con_fops;
+#endif
+    console->type = TTY_DRIVER_TYPE_CONSOLE;
+    console->subtype = SERIAL_TYPE_NORMAL;
+    console->driver = iodev;
+
+    console->pgrp = -1;
+    console->session = -1;
+    console->foreground = RT_NULL;
+    rt_wqueue_init(&console->wait_queue);
+
+    tty_ldisc_init(console);
+
+extern struct termios tty_std_termios;
+    console->init_termios = tty_std_termios;
+    console->init_termios.c_cflag =
+        B9600 | CS8 | CREAD | HUPCL; /* is normally B9600 default... */
+    console->init_termios.__c_ispeed = 9600;
+    console->init_termios.__c_ospeed = 9600;
+
+    console_ldata_init(console);
+    console->init_flag = TTY_INIT_FLAG_REGED;
+exit:
+    rt_hw_interrupt_enable(level);
+    return ret;
+}

+ 19 - 0
components/drivers/tty/include/console.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#ifndef __CONSOLE_
+#define __CONSOLE_
+#include <rtthread.h>
+#include "tty.h"
+
+struct tty_struct *console_tty_get(void);
+struct rt_device *console_get_iodev(void);
+struct rt_device *console_set_iodev(struct rt_device *iodev);
+rt_err_t console_register(const char *name, struct rt_device *iodev);
+#endif

+ 63 - 40
components/libc/termios/posix_termios.h → components/drivers/tty/include/posix_termios.h

@@ -1,14 +1,15 @@
 /*
- * Copyright (c) 2006-2018, RT-Thread Development Team
+ * Copyright (c) 2006-2021, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Change Logs:
  * Date           Author       Notes
  * 2017/08/30     Bernard      The first version
+ * 2021/12/10     linzhenxing  put tty system
  */
-#ifndef TERMIOS_H__
-#define TERMIOS_H__
+#ifndef KTERMIOS_H__
+#define KTERMIOS_H__
 
 #include <rtthread.h>
 #include <sys/types.h>
@@ -34,6 +35,7 @@ struct termios {
     speed_t __c_ospeed;
 };
 
+/* c_cc characters */
 #define VINTR     0
 #define VQUIT     1
 #define VERASE    2
@@ -52,6 +54,7 @@ struct termios {
 #define VLNEXT   15
 #define VEOL2    16
 
+/* c_iflag bits */
 #define IGNBRK  0000001
 #define BRKINT  0000002
 #define IGNPAR  0000004
@@ -68,38 +71,44 @@ struct termios {
 #define IMAXBEL 0020000
 #define IUTF8   0040000
 
+/* c_oflag bits */
 #define OPOST  0000001
-#define OLCUC  0000002
-#define ONLCR  0000004
+#define ONLCR  0000002
+#define OLCUC  0000004
+
 #define OCRNL  0000010
 #define ONOCR  0000020
 #define ONLRET 0000040
-#define OFILL  0000100
-#define OFDEL  0000200
-#define NLDLY  0000400
-#define NL0    0000000
-#define NL1    0000400
-#define CRDLY  0003000
-#define CR0    0000000
-#define CR1    0001000
-#define CR2    0002000
-#define CR3    0003000
-#define TABDLY 0014000
-#define TAB0   0000000
-#define TAB1   0004000
-#define TAB2   0010000
-#define TAB3   0014000
-#define BSDLY  0020000
-#define BS0    0000000
-#define BS1    0020000
-#define FFDLY  0100000
-#define FF0    0000000
-#define FF1    0100000
-
-#define VTDLY  0040000
-#define VT0    0000000
-#define VT1    0040000
 
+#define OFILL   00000100
+#define OFDEL   00000200
+#define NLDLY   00001400
+#define   NL0   00000000
+#define   NL1   00000400
+#define   NL2   00001000
+#define   NL3   00001400
+#define TABDLY  00006000
+#define   TAB0  00000000
+#define   TAB1  00002000
+#define   TAB2  00004000
+#define   TAB3  00006000
+#define CRDLY   00030000
+#define   KCR0  00000000
+#define   KCR1  00010000
+#define   KCR2  00020000
+#define   KCR3  00030000
+#define FFDLY   00040000
+#define   FF0   00000000
+#define   FF1   00040000
+#define BSDLY   00100000
+#define   BS0   00000000
+#define   BS1   00100000
+#define VTDLY   00200000
+#define   VT0   00000000
+#define   VT1   00200000
+#define XTABS   01000000
+
+/* c_cflag bit meaning */
 #define B0       0000000
 #define B50      0000001
 #define B75      0000002
@@ -145,15 +154,23 @@ struct termios {
 #define HUPCL  0002000
 #define CLOCAL 0004000
 
-#define ISIG   0000001
-#define ICANON 0000002
-#define ECHO   0000010
-#define ECHOE  0000020
-#define ECHOK  0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define IEXTEN 0100000
+/* c_lflag bits */
+#define ISIG    0000001
+#define ICANON  0000002
+#define XCASE   0000004
+#define ECHO    0000010
+#define ECHOE   0000020
+#define ECHOK   0000040
+#define ECHONL  0000100
+#define NOFLSH  0000200
+#define TOSTOP  0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE  0004000
+#define FLUSHO  0010000
+#define PENDIN  0040000
+#define IEXTEN  0100000
+#define EXTPROC 0200000
 
 #define TCOOFF 0
 #define TCOON  1
@@ -184,7 +201,13 @@ struct termios {
 #define PENDIN  0040000
 #define EXTPROC 0200000
 
-#define XTABS  0014000
+/*  intr=^C     quit=^|     erase=del   kill=^U
+    eof=^D      vtime=\0    vmin=\1     sxtc=\0
+    start=^Q    stop=^S     susp=^Z     eol=\0
+    reprint=^R  discard=^U  werase=^W   lnext=^V
+    eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
 
 speed_t cfgetospeed (const struct termios *);
 speed_t cfgetispeed (const struct termios *);

+ 477 - 0
components/drivers/tty/include/tty.h

@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#ifndef __TTY_H__
+#define __TTY_H__
+#include <rthw.h>
+#include <rtthread.h>
+#include <tty_ldisc.h>
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#endif
+#if defined(RT_USING_POSIX)
+#include <dfs_poll.h>
+#include <posix_termios.h>
+#endif
+
+#define current lwp_self()
+#define __DISABLED_CHAR '\0'
+
+/*
+ * When a break, frame error, or parity error happens, these codes are
+ * stuffed into the flags buffer.
+ */
+#define TTY_NORMAL  0
+#define TTY_BREAK   1
+#define TTY_FRAME   2
+#define TTY_PARITY  3
+#define TTY_OVERRUN 4
+
+#define INTR_CHAR(tty) ((tty)->init_termios.c_cc[VINTR])
+#define QUIT_CHAR(tty) ((tty)->init_termios.c_cc[VQUIT])
+#define ERASE_CHAR(tty) ((tty)->init_termios.c_cc[VERASE])
+#define KILL_CHAR(tty) ((tty)->init_termios.c_cc[VKILL])
+#define EOF_CHAR(tty) ((tty)->init_termios.c_cc[VEOF])
+#define TIME_CHAR(tty) ((tty)->init_termios.c_cc[VTIME])
+#define MIN_CHAR(tty) ((tty)->init_termios.c_cc[VMIN])
+#define SWTC_CHAR(tty) ((tty)->init_termios.c_cc[VSWTC])
+#define START_CHAR(tty) ((tty)->init_termios.c_cc[VSTART])
+#define STOP_CHAR(tty) ((tty)->init_termios.c_cc[VSTOP])
+#define SUSP_CHAR(tty) ((tty)->init_termios.c_cc[VSUSP])
+#define EOL_CHAR(tty) ((tty)->init_termios.c_cc[VEOL])
+#define REPRINT_CHAR(tty) ((tty)->init_termios.c_cc[VREPRINT])
+#define DISCARD_CHAR(tty) ((tty)->init_termios.c_cc[VDISCARD])
+#define WERASE_CHAR(tty) ((tty)->init_termios.c_cc[VWERASE])
+#define LNEXT_CHAR(tty) ((tty)->init_termios.c_cc[VLNEXT])
+#define EOL2_CHAR(tty) ((tty)->init_termios.c_cc[VEOL2])
+
+#define _I_FLAG(tty,f)  ((tty)->init_termios.c_iflag & (f))
+#define _O_FLAG(tty,f)  ((tty)->init_termios.c_oflag & (f))
+#define _C_FLAG(tty,f)  ((tty)->init_termios.c_cflag & (f))
+#define _L_FLAG(tty,f)  ((tty)->init_termios.c_lflag & (f))
+
+#define I_IGNBRK(tty)   _I_FLAG((tty),IGNBRK)
+#define I_BRKINT(tty)   _I_FLAG((tty),BRKINT)
+#define I_IGNPAR(tty)   _I_FLAG((tty),IGNPAR)
+#define I_PARMRK(tty)   _I_FLAG((tty),PARMRK)
+#define I_INPCK(tty)    _I_FLAG((tty),INPCK)
+#define I_ISTRIP(tty)   _I_FLAG((tty),ISTRIP)
+#define I_INLCR(tty)    _I_FLAG((tty),INLCR)
+#define I_IGNCR(tty)    _I_FLAG((tty),IGNCR)
+#define I_ICRNL(tty)    _I_FLAG((tty),ICRNL)
+#define I_IUCLC(tty)    _I_FLAG((tty),IUCLC)
+#define I_IXON(tty)     _I_FLAG((tty),IXON)
+#define I_IXANY(tty)    _I_FLAG((tty),IXANY)
+#define I_IXOFF(tty)    _I_FLAG((tty),IXOFF)
+#define I_IMAXBEL(tty)  _I_FLAG((tty),IMAXBEL)
+#define I_IUTF8(tty)    _I_FLAG((tty), IUTF8)
+
+#define O_OPOST(tty)    _O_FLAG((tty),OPOST)
+#define O_OLCUC(tty)    _O_FLAG((tty),OLCUC)
+#define O_ONLCR(tty)    _O_FLAG((tty),ONLCR)
+#define O_OCRNL(tty)    _O_FLAG((tty),OCRNL)
+#define O_ONOCR(tty)    _O_FLAG((tty),ONOCR)
+#define O_ONLRET(tty)   _O_FLAG((tty),ONLRET)
+#define O_OFILL(tty)    _O_FLAG((tty),OFILL)
+#define O_OFDEL(tty)    _O_FLAG((tty),OFDEL)
+#define O_NLDLY(tty)    _O_FLAG((tty),NLDLY)
+#define O_CRDLY(tty)    _O_FLAG((tty),CRDLY)
+#define O_TABDLY(tty)   _O_FLAG((tty),TABDLY)
+#define O_BSDLY(tty)    _O_FLAG((tty),BSDLY)
+#define O_VTDLY(tty)    _O_FLAG((tty),VTDLY)
+#define O_FFDLY(tty)    _O_FLAG((tty),FFDLY)
+
+#define C_BAUD(tty)     _C_FLAG((tty),CBAUD)
+#define C_CSIZE(tty)    _C_FLAG((tty),CSIZE)
+#define C_CSTOPB(tty)   _C_FLAG((tty),CSTOPB)
+#define C_CREAD(tty)    _C_FLAG((tty),CREAD)
+#define C_PARENB(tty)   _C_FLAG((tty),PARENB)
+#define C_PARODD(tty)   _C_FLAG((tty),PARODD)
+#define C_HUPCL(tty)    _C_FLAG((tty),HUPCL)
+#define C_CLOCAL(tty)   _C_FLAG((tty),CLOCAL)
+#define C_CIBAUD(tty)   _C_FLAG((tty),CIBAUD)
+#define C_CRTSCTS(tty)  _C_FLAG((tty),CRTSCTS)
+
+#define L_ISIG(tty)     _L_FLAG((tty),ISIG)
+#define L_ICANON(tty)   _L_FLAG((tty),ICANON)
+#define L_XCASE(tty)    _L_FLAG((tty),XCASE)
+#define L_ECHO(tty)     _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty)    _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty)    _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty)   _L_FLAG((tty),ECHONL)
+#define L_NOFLSH(tty)   _L_FLAG((tty),NOFLSH)
+#define L_TOSTOP(tty)   _L_FLAG((tty),TOSTOP)
+#define L_ECHOCTL(tty)  _L_FLAG((tty),ECHOCTL)
+#define L_ECHOPRT(tty)  _L_FLAG((tty),ECHOPRT)
+#define L_ECHOKE(tty)   _L_FLAG((tty),ECHOKE)
+#define L_FLUSHO(tty)   _L_FLAG((tty),FLUSHO)
+#define L_PENDIN(tty)   _L_FLAG((tty),PENDIN)
+#define L_IEXTEN(tty)   _L_FLAG((tty),IEXTEN)
+#define L_EXTPROC(tty)  _L_FLAG((tty), EXTPROC)
+
+/*
+ * Where all of the state associated with a tty is kept while the tty
+ * is open.  Since the termios state should be kept even if the tty
+ * has been closed --- for things like the baud rate, etc --- it is
+ * not stored here, but rather a pointer to the real state is stored
+ * here.  Possible the winsize structure should have the same
+ * treatment, but (1) the default 80x24 is usually right and (2) it's
+ * most often used by a windowing system, which will set the correct
+ * size each time the window is created or resized anyway.
+ *                      - TYT, 9/14/92
+ */
+struct tty_struct
+{
+    struct rt_device parent;
+    int type;
+    int subtype;
+    int init_flag;
+    int index;  //for pty
+    int pts_lock;   //for pty
+
+    struct tty_struct *other_struct; //for pty
+
+    struct winsize winsize;
+    struct termios init_termios;
+    struct rt_mutex mutex;
+
+    pid_t pgrp;
+    pid_t session;
+    struct rt_lwp *foreground;
+
+    struct tty_ldisc *ldisc;
+    void *disc_data;
+    struct rt_device *driver;
+
+    struct rt_wqueue wait_queue;
+
+#define RT_TTY_BUF 1024
+    rt_list_t tty_drivers;
+};
+
+enum
+{
+    TTY_INIT_FLAG_NONE = 0,
+    TTY_INIT_FLAG_ALLOCED,
+    TTY_INIT_FLAG_REGED,
+    TTY_INIT_FLAG_INITED,
+};
+
+#define TTY_DRIVER_TYPE_SYSTEM      0x0001
+#define TTY_DRIVER_TYPE_CONSOLE     0x0002
+#define TTY_DRIVER_TYPE_SERIAL      0x0003
+#define TTY_DRIVER_TYPE_PTY     0x0004
+#define TTY_DRIVER_TYPE_SCC     0x0005  /* scc driver */
+#define TTY_DRIVER_TYPE_SYSCONS     0x0006
+
+/* tty magic number */
+#define TTY_MAGIC       0x5401
+
+/*
+ * These bits are used in the flags field of the tty structure.
+ *
+ * So that interrupts won't be able to mess up the queues,
+ * copy_to_cooked must be atomic with respect to itself, as must
+ * tty->write.  Thus, you must use the inline functions set_bit() and
+ * clear_bit() to make things atomic.
+ */
+#define TTY_THROTTLED 0
+#define TTY_IO_ERROR 1
+#define TTY_OTHER_CLOSED 2
+#define TTY_EXCLUSIVE 3
+#define TTY_DEBUG 4
+#define TTY_DO_WRITE_WAKEUP 5
+#define TTY_PUSH 6
+#define TTY_CLOSING 7
+#define TTY_DONT_FLIP 8
+#define TTY_HW_COOK_OUT 14
+#define TTY_HW_COOK_IN 15
+#define TTY_PTY_LOCK 16
+#define TTY_NO_WRITE_SPLIT 17
+
+/*
+ * These bits are used in the flags field of the tty structure.
+ *
+ * So that interrupts won't be able to mess up the queues,
+ * copy_to_cooked must be atomic with respect to itself, as must
+ * tty->write.  Thus, you must use the inline functions set_bit() and
+ * clear_bit() to make things atomic.
+ */
+#define TTY_THROTTLED 0
+#define TTY_IO_ERROR 1
+#define TTY_OTHER_CLOSED 2
+#define TTY_EXCLUSIVE 3
+#define TTY_DEBUG 4
+#define TTY_DO_WRITE_WAKEUP 5
+#define TTY_PUSH 6
+#define TTY_CLOSING 7
+#define TTY_DONT_FLIP 8
+#define TTY_HW_COOK_OUT 14
+#define TTY_HW_COOK_IN 15
+#define TTY_PTY_LOCK 16
+#define TTY_NO_WRITE_SPLIT 17
+
+#define NR_LDISCS       30
+
+/* line disciplines */
+#define N_TTY       0
+#define N_SLIP      1
+#define N_MOUSE     2
+#define N_PPP       3
+#define N_STRIP     4
+#define N_AX25      5
+#define N_X25       6   /* X.25 async */
+#define N_6PACK     7
+#define N_MASC      8   /* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964     9   /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL  10  /* Reserved for Profibus */
+#define N_IRDA      11  /* Linux IrDa - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK  12  /* SMS block mode - for talking to GSM data */
+                /* cards about SMS messages */
+#define N_HDLC      13  /* synchronous HDLC */
+#define N_SYNC_PPP  14  /* synchronous PPP */
+#define N_HCI       15  /* Bluetooth HCI UART */
+#define N_GIGASET_M101  16  /* Siemens Gigaset M101 serial DECT adapter */
+#define N_SLCAN     17  /* Serial / USB serial CAN Adaptors */
+#define N_PPS       18  /* Pulse per Second */
+#define N_V253      19  /* Codec control over voice modem */
+#define N_CAIF      20      /* CAIF protocol for talking to modems */
+#define N_GSM0710   21  /* GSM 0710 Mux */
+#define N_TI_WL     22  /* for TI's WL BT, FM, GPS combo chips */
+#define N_TRACESINK 23  /* Trace data routing for MIPI P1149.7 */
+#define N_TRACEROUTER   24  /* Trace data routing for MIPI P1149.7 */
+#define N_NCI       25  /* NFC NCI UART */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA         0
+#define TIOCPKT_FLUSHREAD    1
+#define TIOCPKT_FLUSHWRITE   2
+#define TIOCPKT_STOP         4
+#define TIOCPKT_START        8
+#define TIOCPKT_NOSTOP      16
+#define TIOCPKT_DOSTOP      32
+
+/* tty driver types */
+#define TTY_DRIVER_TYPE_SYSTEM      0x0001
+#define TTY_DRIVER_TYPE_CONSOLE     0x0002
+#define TTY_DRIVER_TYPE_SERIAL      0x0003
+#define TTY_DRIVER_TYPE_PTY     0x0004
+#define TTY_DRIVER_TYPE_SCC     0x0005  /* scc driver */
+#define TTY_DRIVER_TYPE_SYSCONS     0x0006
+
+/* pty subtypes */
+#define PTY_TYPE_MASTER         0x0001
+#define PTY_TYPE_SLAVE          0x0002
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL  1
+
+#define max(a, b) ({\
+        typeof(a) _a = a;\
+        typeof(b) _b = b;\
+        _a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+        typeof(a) _a = a;\
+        typeof(b) _b = b;\
+        _a < _b ? _a : _b; })
+
+void tty_set_fops(struct dfs_file_ops *fops);
+void console_set_fops(struct dfs_file_ops *fops);
+void mutex_lock(rt_mutex_t mutex);
+void mutex_unlock(rt_mutex_t mutex);
+int __tty_check_change(struct tty_struct *tty, int sig);
+int tty_check_change(struct tty_struct *tty);
+
+rt_inline struct rt_wqueue *wait_queue_get(struct rt_lwp *lwp, struct tty_struct *tty)
+{
+    if (lwp == RT_NULL)
+    {
+        return &tty->wait_queue;
+    }
+    return &lwp->wait_queue;
+}
+
+rt_inline struct rt_wqueue *wait_queue_current_get(struct rt_lwp *lwp, struct tty_struct *tty)
+{
+    return wait_queue_get(lwp, tty);
+}
+
+rt_inline void tty_wakeup_check(struct tty_struct *tty)
+{
+    struct rt_wqueue *wq = NULL;
+
+    wq = wait_queue_current_get(tty->foreground, tty);
+    rt_wqueue_wakeup(wq, (void*)POLLIN);
+}
+
+rt_inline int set_bit(int nr,int *addr)
+{
+    int mask, retval, level;
+
+    addr += nr >> 5;
+    mask = 1 << (nr & 0x1f);
+    level = rt_hw_interrupt_disable();
+    retval = (mask & *addr) != 0;
+    *addr |= mask;
+    rt_hw_interrupt_enable(level);
+    return retval;
+}
+
+rt_inline int clear_bit(int nr, int *addr)
+{
+    int mask, retval, level;
+
+    addr += nr >> 5;
+    mask = 1 << (nr & 0x1f);
+    level = rt_hw_interrupt_disable();
+    retval = (mask & *addr) != 0;
+    *addr &= ~mask;
+    rt_hw_interrupt_enable(level);
+    return retval;
+}
+
+rt_inline int test_bit(int nr, int *addr)
+{
+    int mask;
+
+    addr += nr >> 5;
+    mask = 1 << (nr & 0x1f);
+    return ((mask & *addr) != 0);
+}
+
+rt_inline int test_and_clear_bit(int nr, volatile void *addr)
+{
+    int mask, retval, level;
+    volatile unsigned int *a = addr;
+
+    a += nr >> 5;
+    mask = 1 << (nr & 0x1f);
+    level = rt_hw_interrupt_disable();
+    retval = (mask & *a) != 0;
+    *a &= ~mask;
+    rt_hw_interrupt_enable(level);
+
+    return retval;
+}
+
+rt_inline unsigned long __ffs(unsigned long word)
+{
+    int num = 0;
+
+#if BITS_PER_LONG == 64
+    if ((word & 0xffffffff) == 0)
+    {
+        num += 32;
+        word >>= 32;
+    }
+#endif
+    if ((word & 0xffff) == 0)
+    {
+        num += 16;
+        word >>= 16;
+    }
+    if ((word & 0xff) == 0)
+    {
+        num += 8;
+        word >>= 8;
+    }
+    if ((word & 0xf) == 0)
+    {
+        num += 4;
+        word >>= 4;
+    }
+    if ((word & 0x3) == 0)
+    {
+        num += 2;
+        word >>= 2;
+    }
+    if ((word & 0x1) == 0)
+    {
+        num += 1;
+    }
+
+    return num;
+}
+#define BITS_PER_LONG       32
+#define BITOP_WORD(nr)      ((nr) / BITS_PER_LONG)
+
+/*
+ * Find the next set bit in a memory region.
+ */
+rt_inline unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+                unsigned long offset)
+{
+    const unsigned long *p = addr + BITOP_WORD(offset);
+    unsigned long result = offset & ~(BITS_PER_LONG-1);
+    unsigned long tmp;
+
+    if (offset >= size)
+    {
+        return size;
+    }
+
+    size -= result;
+    offset %= BITS_PER_LONG;
+    if (offset)
+    {
+        tmp = *(p++);
+        tmp &= (~0UL << offset);
+        if (size < BITS_PER_LONG)
+        {
+            goto found_first;
+        }
+
+        if (tmp)
+        {
+            goto found_middle;
+        }
+
+        size -= BITS_PER_LONG;
+        result += BITS_PER_LONG;
+    }
+
+    while (size & ~(BITS_PER_LONG-1))
+    {
+        if ((tmp = *(p++)))
+        {
+            goto found_middle;
+        }
+
+        result += BITS_PER_LONG;
+        size -= BITS_PER_LONG;
+    }
+
+    if (!size)
+    {
+        return result;
+    }
+
+    tmp = *p;
+
+found_first:
+    tmp &= (~0UL >> (BITS_PER_LONG - size));
+    if (tmp == 0UL)     /* Are any bits set? */
+    {
+        return result + size;   /* Nope. */
+    }
+
+found_middle:
+    return result + __ffs(tmp);
+}
+
+/*create by tty_ioctl.c*/
+int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *arg);
+
+/*create by n_tty.c*/
+void console_ldata_init(struct tty_struct *tty);
+int n_tty_receive_buf(struct tty_struct *tty, char *cp, int count);
+void n_tty_init(void);
+
+#endif /*__TTY_H__*/

+ 56 - 0
components/drivers/tty/include/tty_ldisc.h

@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#ifndef __TTY_LDISC_
+#define __TTY_LDISC_
+#include <rtthread.h>
+#include <dfs.h>
+#include <dfs_fs.h>
+#include <tty.h>
+#if defined(RT_USING_POSIX)
+#include <posix_termios.h>
+#endif
+struct tty_struct;
+
+struct tty_ldisc_ops
+{
+    char    *name;
+    int num;
+
+    int (*open)     (struct dfs_fd *fd);
+    int (*close)    (struct tty_struct *tty);
+    int (*ioctl)    (struct dfs_fd *fd, int cmd, void *args);
+    int (*read)     (struct dfs_fd *fd, void *buf, size_t count);
+    int (*write)    (struct dfs_fd *fd, const void *buf, size_t count);
+    int (*flush)    (struct dfs_fd *fd);
+    int (*lseek)    (struct dfs_fd *fd, off_t offset);
+    int (*getdents) (struct dfs_fd *fd, struct dirent *dirp, uint32_t count);
+
+    int (*poll)     (struct dfs_fd *fd, struct rt_pollreq *req);
+    void (*set_termios) (struct tty_struct *tty, struct termios *old);
+    int (*receive_buf) (struct tty_struct *tty,char *cp, int count);
+
+    int refcount;
+};
+
+struct tty_ldisc
+{
+    struct tty_ldisc_ops *ops;
+    struct tty_struct *tty;
+};
+
+#define TTY_LDISC_MAGIC 0x5403
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
+void tty_ldisc_kill(struct tty_struct *tty);
+void tty_ldisc_init(struct tty_struct *tty);
+void tty_ldisc_release(struct tty_struct *tty);
+void n_tty_init(void);
+
+#endif // __TTY_LDISC_

+ 2039 - 0
components/drivers/tty/n_tty.c

@@ -0,0 +1,2039 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#include <stddef.h>
+#include <ctype.h>
+#include <tty.h>
+#if defined(RT_USING_POSIX)
+#include <posix_termios.h>
+#endif
+
+#define DBG_TAG               "N_TTY"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL               DBG_LOG
+#else
+#define DBG_LVL               DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+/* number of characters left in xmit buffer before select has we have room */
+#define WAKEUP_CHARS 256
+
+/*
+ * This defines the low- and high-watermarks for throttling and
+ * unthrottling the TTY driver.  These watermarks are used for
+ * controlling the space in the read buffer.
+ */
+#define TTY_THRESHOLD_THROTTLE      128 /* now based on remaining room */
+#define TTY_THRESHOLD_UNTHROTTLE    128
+
+/*
+ * Special byte codes used in the echo buffer to represent operations
+ * or special handling of characters.  Bytes in the echo buffer that
+ * are not part of such special blocks are treated as normal character
+ * codes.
+ */
+#define ECHO_OP_START 0xff
+#define ECHO_OP_MOVE_BACK_COL 0x80
+#define ECHO_OP_SET_CANON_COL 0x81
+#define ECHO_OP_ERASE_TAB 0x82
+
+#define ECHO_COMMIT_WATERMARK   256
+#define ECHO_BLOCK      256
+#define ECHO_DISCARD_WATERMARK  RT_TTY_BUF - (ECHO_BLOCK + 32)
+
+void mutex_lock(rt_mutex_t mutex)
+{
+    rt_err_t result = -RT_EBUSY;
+
+    while (result == -RT_EBUSY)
+    {
+        result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
+    }
+
+    if (result != RT_EOK)
+    {
+        RT_ASSERT(0);
+    }
+    return;
+}
+
+void mutex_unlock(rt_mutex_t mutex)
+{
+    rt_mutex_release(mutex);
+    return;
+}
+struct n_tty_data
+{
+    /* producer-published */
+    size_t read_head;
+    size_t commit_head;
+    size_t canon_head;
+    size_t echo_head;
+    size_t echo_commit;
+    size_t echo_mark;
+    unsigned long char_map[256];
+
+    /* non-atomic */
+    rt_bool_t no_room;
+    /* must hold exclusive termios_rwsem to reset these */
+    unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+    unsigned char push:1;
+
+    /* shared by producer and consumer */
+    char read_buf[RT_TTY_BUF];
+    unsigned long read_flags[RT_TTY_BUF];
+    unsigned char echo_buf[RT_TTY_BUF];
+
+    /* consumer-published */
+    size_t read_tail;
+    size_t line_start;
+
+    /* protected by output lock */
+    unsigned int column;
+    unsigned int canon_column;
+    size_t echo_tail;
+
+    rt_mutex_t atomic_read_lock;
+    rt_mutex_t output_lock;
+};
+
+static inline size_t read_cnt(struct n_tty_data *ldata)
+{
+    return ldata->read_head - ldata->read_tail;
+}
+
+static inline char read_buf(struct n_tty_data *ldata, size_t i)
+{
+    return ldata->read_buf[i & (RT_TTY_BUF - 1)];
+}
+
+static inline char *read_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+    return &ldata->read_buf[i & (RT_TTY_BUF - 1)];
+}
+
+static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
+{
+    return ldata->echo_buf[i & (RT_TTY_BUF - 1)];
+}
+
+static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+    return &ldata->echo_buf[i & (RT_TTY_BUF - 1)];
+}
+
+/**
+ *  put_tty_queue       -   add character to tty
+ *  @c: character
+ *  @ldata: n_tty data
+ *
+ *  Add a character to the tty read_buf queue.
+ *
+ *  n_tty_receive_buf()/producer path:
+ *      caller holds non-exclusive termios_rwsem
+ */
+
+static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
+{
+    *read_buf_addr(ldata, ldata->read_head) = c;
+    ldata->read_head++;
+}
+
+/**
+ *  reset_buffer_flags  -   reset buffer state
+ *  @tty: terminal to reset
+ *
+ *  Reset the read buffer counters and clear the flags.
+ *  Called from n_tty_open() and n_tty_flush_buffer().
+ *
+ *  Locking: caller holds exclusive termios_rwsem
+ *       (or locking is not required)
+ */
+
+static void reset_buffer_flags(struct n_tty_data *ldata)
+{
+    ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
+    ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
+    ldata->commit_head = 0;
+    ldata->echo_mark = 0;
+    ldata->line_start = 0;
+
+    ldata->erasing = 0;
+    rt_memset(ldata->read_flags, 0, RT_TTY_BUF);
+    ldata->push = 0;
+}
+
+/**
+ *  add_echo_byte   -   add a byte to the echo buffer
+ *  @c: unicode byte to echo
+ *  @ldata: n_tty data
+ *
+ *  Add a character or operation byte to the echo buffer.
+ */
+
+static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
+{
+    *echo_buf_addr(ldata, ldata->echo_head++) = c;
+}
+
+/**
+ *  echo_move_back_col  -   add operation to move back a column
+ *  @ldata: n_tty data
+ *
+ *  Add an operation to the echo buffer to move back one column.
+ */
+
+static void echo_move_back_col(struct n_tty_data *ldata)
+{
+    add_echo_byte(ECHO_OP_START, ldata);
+    add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
+}
+
+/**
+ *  echo_set_canon_col  -   add operation to set the canon column
+ *  @ldata: n_tty data
+ *
+ *  Add an operation to the echo buffer to set the canon column
+ *  to the current column.
+ */
+
+static void echo_set_canon_col(struct n_tty_data *ldata)
+{
+    add_echo_byte(ECHO_OP_START, ldata);
+    add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
+}
+
+/**
+ *  echo_erase_tab  -   add operation to erase a tab
+ *  @num_chars: number of character columns already used
+ *  @after_tab: true if num_chars starts after a previous tab
+ *  @ldata: n_tty data
+ *
+ *  Add an operation to the echo buffer to erase a tab.
+ *
+ *  Called by the eraser function, which knows how many character
+ *  columns have been used since either a previous tab or the start
+ *  of input.  This information will be used later, along with
+ *  canon column (if applicable), to go back the correct number
+ *  of columns.
+ */
+
+static void echo_erase_tab(unsigned int num_chars, int after_tab,
+               struct n_tty_data *ldata)
+{
+    add_echo_byte(ECHO_OP_START, ldata);
+    add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
+
+    /* We only need to know this modulo 8 (tab spacing) */
+    num_chars &= 7;
+
+    /* Set the high bit as a flag if num_chars is after a previous tab */
+    if (after_tab)
+    {
+        num_chars |= 0x80;
+    }
+
+    add_echo_byte(num_chars, ldata);
+}
+
+/**
+ *  echo_char_raw   -   echo a character raw
+ *  @c: unicode byte to echo
+ *  @tty: terminal device
+ *
+ *  Echo user input back onto the screen. This must be called only when
+ *  L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *  This variant does not treat control characters specially.
+ */
+
+static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
+{
+    if (c == ECHO_OP_START)
+    {
+        add_echo_byte(ECHO_OP_START, ldata);
+        add_echo_byte(ECHO_OP_START, ldata);
+    }
+    else
+    {
+        add_echo_byte(c, ldata);
+    }
+}
+
+/**
+ *  echo_char   -   echo a character
+ *  @c: unicode byte to echo
+ *  @tty: terminal device
+ *
+ *  Echo user input back onto the screen. This must be called only when
+ *  L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *  This variant tags control characters to be echoed as "^X"
+ *  (where X is the letter representing the control char).
+ */
+
+static void echo_char(unsigned char c, struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    if (c == ECHO_OP_START)
+    {
+        add_echo_byte(ECHO_OP_START, ldata);
+        add_echo_byte(ECHO_OP_START, ldata);
+    }
+    else
+    {
+        if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
+        {
+            add_echo_byte(ECHO_OP_START, ldata);
+        }
+        add_echo_byte(c, ldata);
+    }
+}
+
+/**
+ *  finish_erasing      -   complete erase
+ *  @ldata: n_tty data
+ */
+
+static inline void finish_erasing(struct n_tty_data *ldata)
+{
+    if (ldata->erasing)
+    {
+        echo_char_raw('/', ldata);
+        ldata->erasing = 0;
+    }
+}
+
+/**
+ *  is_utf8_continuation    -   utf8 multibyte check
+ *  @c: byte to check
+ *
+ *  Returns true if the utf8 character 'c' is a multibyte continuation
+ *  character. We use this to correctly compute the on screen size
+ *  of the character when printing
+ */
+
+static inline int is_utf8_continuation(unsigned char c)
+{
+    return (c & 0xc0) == 0x80;
+}
+
+/**
+ *  is_continuation     -   multibyte check
+ *  @c: byte to check
+ *
+ *  Returns true if the utf8 character 'c' is a multibyte continuation
+ *  character and the terminal is in unicode mode.
+ */
+
+static inline int is_continuation(unsigned char c, struct tty_struct *tty)
+{
+    return I_IUTF8(tty) && is_utf8_continuation(c);
+}
+
+/**
+ *  eraser      -   handle erase function
+ *  @c: character input
+ *  @tty: terminal device
+ *
+ *  Perform erase and necessary output when an erase character is
+ *  present in the stream from the driver layer. Handles the complexities
+ *  of UTF-8 multibyte symbols.
+ *
+ *  n_tty_receive_buf()/producer path:
+ *      caller holds non-exclusive termios_rwsem
+ */
+
+static void eraser(unsigned char c, struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    enum { KERASE, WERASE, KILL } kill_type;
+    size_t head = 0;
+    size_t cnt = 0;
+    int seen_alnums = 0;
+
+    if (ldata->read_head == ldata->canon_head)
+    {
+        /* process_output('\a', tty); */ /* what do you think? */
+        return;
+    }
+
+    if (c == ERASE_CHAR(tty))
+    {
+        kill_type = KERASE;
+    }
+    else if (c == WERASE_CHAR(tty))
+    {
+        kill_type = WERASE;
+    }
+    else
+    {
+        if (!L_ECHO(tty))
+        {
+            ldata->read_head = ldata->canon_head;
+            return;
+        }
+
+        if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty))
+        {
+            ldata->read_head = ldata->canon_head;
+            finish_erasing(ldata);
+            echo_char(KILL_CHAR(tty), tty);
+            /* Add a newline if ECHOK is on and ECHOKE is off. */
+            if (L_ECHOK(tty))
+            {
+                echo_char_raw('\n', ldata);
+            }
+            return;
+        }
+        kill_type = KILL;
+    }
+
+    seen_alnums = 0;
+    while (ldata->read_head != ldata->canon_head)
+    {
+        head = ldata->read_head;
+
+        /* erase a single possibly multibyte character */
+        do
+        {
+            head--;
+            c = read_buf(ldata, head);
+        } while (is_continuation(c, tty) && head != ldata->canon_head);
+
+        /* do not partially erase */
+        if (is_continuation(c, tty))
+        {
+            break;
+        }
+
+        if (kill_type == WERASE)
+        {
+            /* Equivalent to BSD's ALTWERASE. */
+            if (isalnum(c) || c == '_')
+            {
+                seen_alnums++;
+            }
+            else if (seen_alnums)
+            {
+                break;
+            }
+        }
+        cnt = ldata->read_head - head;
+        ldata->read_head = head;
+        if (L_ECHO(tty))
+        {
+            if (L_ECHOPRT(tty))
+            {
+                if (!ldata->erasing)
+                {
+                    echo_char_raw('\\', ldata);
+                    ldata->erasing = 1;
+                }
+                /* if cnt > 1, output a multi-byte character */
+                echo_char(c, tty);
+                while (--cnt > 0)
+                {
+                    head++;
+                    echo_char_raw(read_buf(ldata, head), ldata);
+                    echo_move_back_col(ldata);
+                }
+            }
+            else if (kill_type == KERASE && !L_ECHOE(tty))
+            {
+                echo_char(ERASE_CHAR(tty), tty);
+            }
+            else if (c == '\t')
+            {
+                unsigned int num_chars = 0;
+                int after_tab = 0;
+                size_t tail = ldata->read_head;
+
+                /*
+                 * Count the columns used for characters
+                 * since the start of input or after a
+                 * previous tab.
+                 * This info is used to go back the correct
+                 * number of columns.
+                 */
+                while (tail != ldata->canon_head)
+                {
+                    tail--;
+                    c = read_buf(ldata, tail);
+                    if (c == '\t')
+                    {
+                        after_tab = 1;
+                        break;
+                    }
+                    else if (iscntrl(c))
+                    {
+                        if (L_ECHOCTL(tty))
+                        {
+                            num_chars += 2;
+                        }
+                    }
+                    else if (!is_continuation(c, tty))
+                    {
+                        num_chars++;
+                    }
+                }
+                echo_erase_tab(num_chars, after_tab, ldata);
+            }
+            else
+            {
+                if (iscntrl(c) && L_ECHOCTL(tty))
+                {
+                    echo_char_raw('\b', ldata);
+                    echo_char_raw(' ', ldata);
+                    echo_char_raw('\b', ldata);
+                }
+                if (!iscntrl(c) || L_ECHOCTL(tty))
+                {
+                    echo_char_raw('\b', ldata);
+                    echo_char_raw(' ', ldata);
+                    echo_char_raw('\b', ldata);
+                }
+            }
+        }
+        if (kill_type == KERASE)
+        {
+            break;
+        }
+    }
+    if (ldata->read_head == ldata->canon_head && L_ECHO(tty))
+    {
+        finish_erasing(ldata);
+    }
+}
+
+/**
+ *  isig        -   handle the ISIG optio
+ *  @sig: signal
+ *  @tty: terminal
+ *
+ *  Called when a signal is being sent due to terminal input.
+ *  Called from the driver receive_buf path so serialized.
+ *
+ *  Performs input and output flush if !NOFLSH. In this context, the echo
+ *  buffer is 'output'. The signal is processed first to alert any current
+ *  readers or writers to discontinue and exit their i/o loops.
+ *
+ *  Locking: ctrl_lock
+ */
+
+static void __isig(int sig, struct tty_struct *tty)
+{
+    struct rt_lwp *lwp = tty->foreground;
+    if (lwp)
+    {
+        lwp_kill(lwp_to_pid(lwp), sig);
+    }
+}
+
+static void isig(int sig, struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    if (L_NOFLSH(tty))
+    {
+        /* signal only */
+        __isig(sig, tty);
+
+    }
+    else
+    { /* signal and flush */
+        __isig(sig, tty);
+
+        /* clear echo buffer */
+        ldata->echo_head = ldata->echo_tail = 0;
+        ldata->echo_mark = ldata->echo_commit = 0;
+
+        /* clear input buffer */
+        reset_buffer_flags(tty->disc_data);
+    }
+}
+
+/**
+ *  do_output_char          -   output one character
+ *  @c: character (or partial unicode symbol)
+ *  @tty: terminal device
+ *  @space: space available in tty driver write buffer
+ *
+ *  This is a helper function that handles one output character
+ *  (including special characters like TAB, CR, LF, etc.),
+ *  doing OPOST processing and putting the results in the
+ *  tty driver's write buffer.
+ *
+ *  Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
+ *  and NLDLY.  They simply aren't relevant in the world today.
+ *  If you ever need them, add them here.
+ *
+ *  Returns the number of bytes of buffer space used or -1 if
+ *  no space left.
+ *
+ *  Locking: should be called under the output_lock to protect
+ *       the column state and space left in the buffer
+ */
+
+static int do_output_char(unsigned char c, struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    int spaces = 0;
+    char *ch = RT_NULL;
+
+    switch (c)
+    {
+    case '\n':
+        if (O_ONLRET(tty))
+        {
+            ldata->column = 0;
+        }
+
+        if (O_ONLCR(tty))
+        {
+            ldata->canon_column = ldata->column = 0;
+            ch = "\r\n";
+            rt_device_write((rt_device_t)tty, -1, ch, 2);
+            return 2;
+        }
+        ldata->canon_column = ldata->column;
+        break;
+    case '\r':
+        if (O_ONOCR(tty) && ldata->column == 0)
+        {
+            return 0;
+        }
+
+        if (O_OCRNL(tty))
+        {
+            c = '\n';
+            if (O_ONLRET(tty))
+            {
+                ldata->canon_column = ldata->column = 0;
+            }
+            break;
+        }
+        ldata->canon_column = ldata->column = 0;
+        break;
+    case '\t':
+        spaces = 8 - (ldata->column & 7);
+        if (O_TABDLY(tty) == XTABS)
+        {
+            ldata->column += spaces;
+            ch = "        ";
+            rt_device_write((rt_device_t)tty, -1, &ch, spaces);
+            return spaces;
+        }
+        ldata->column += spaces;
+        break;
+    case '\b':
+        if (ldata->column > 0)
+        {
+            ldata->column--;
+        }
+        ch = "\b \b";
+        rt_device_write((rt_device_t)tty, -1, ch, strlen(ch));
+        return 1;
+    default:
+        if (!iscntrl(c))
+        {
+            if (O_OLCUC(tty))
+            {
+                c = toupper(c);
+            }
+
+            if (!is_continuation(c, tty))
+            {
+                ldata->column++;
+            }
+        }
+        break;
+    }
+
+    rt_device_write((rt_device_t)tty, -1, &c, 1);
+    return 1;
+}
+
+/**
+ *  process_output          -   output post processor
+ *  @c: character (or partial unicode symbol)
+ *  @tty: terminal device
+ *
+ *  Output one character with OPOST processing.
+ *  Returns -1 when the output device is full and the character
+ *  must be retried.
+ *
+ *  Locking: output_lock to protect column state and space left
+ *       (also, this is called from n_tty_write under the
+ *        tty layer write lock)
+ */
+
+static int process_output(unsigned char c, struct tty_struct *tty)
+{
+    int retval = 0;
+    int level = 0;
+
+    level = rt_hw_interrupt_disable();
+    retval = do_output_char(c, tty);
+    rt_hw_interrupt_enable(level);
+    if (retval < 0)
+    {
+        return -1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+/**
+ *  process_output_block        -   block post processor
+ *  @tty: terminal device
+ *  @buf: character buffer
+ *  @nr: number of bytes to output
+ *
+ *  Output a block of characters with OPOST processing.
+ *  Returns the number of characters output.
+ *
+ *  This path is used to speed up block console writes, among other
+ *  things when processing blocks of output data. It handles only
+ *  the simple cases normally found and helps to generate blocks of
+ *  symbols for the console driver and thus improve performance.
+ *
+ *  Locking: output_lock to protect column state and space left
+ *       (also, this is called from n_tty_write under the
+ *        tty layer write lock)
+ */
+
+static ssize_t process_output_block(struct tty_struct *tty,
+                    const char *buf, unsigned int nr)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    int i = 0;
+    ssize_t size = 0;
+    const char *cp = RT_NULL;
+    int level = 0;
+
+    level = rt_hw_interrupt_disable();
+
+    for (i = 0, cp = buf; i < nr; i++, cp++)
+    {
+        char c = *cp;
+
+        switch (c)
+        {
+        case '\n':
+            if (O_ONLRET(tty))
+            {
+                ldata->column = 0;
+            }
+
+            if (O_ONLCR(tty))
+            {
+                goto break_out;
+            }
+            ldata->canon_column = ldata->column;
+            break;
+        case '\r':
+            if (O_ONOCR(tty) && ldata->column == 0)
+            {
+                goto break_out;
+            }
+
+            if (O_OCRNL(tty))
+            {
+                goto break_out;
+            }
+
+            ldata->canon_column = ldata->column = 0;
+            break;
+        case '\t':
+            goto break_out;
+        case '\b':
+            if (ldata->column > 0)
+            {
+                ldata->column--;
+            }
+            break;
+        default:
+            if (!iscntrl(c))
+            {
+                if (O_OLCUC(tty))
+                {
+                    goto break_out;
+                }
+
+                if (!is_continuation(c, tty))
+                {
+                    ldata->column++;
+                }
+            }
+            break;
+        }
+    }
+break_out:
+    size = rt_device_write((rt_device_t)tty, -1, buf, i);
+    rt_hw_interrupt_enable(level);
+    return size;
+}
+
+static size_t __process_echoes(struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    size_t tail = 0;
+    unsigned char c = 0;
+    char ch = 0;
+
+    tail = ldata->echo_tail;
+    while (ldata->echo_commit != tail)
+    {
+        c = echo_buf(ldata, tail);
+        if (c == ECHO_OP_START)
+        {
+            unsigned char op = 0;
+
+            /*
+             * If the buffer byte is the start of a multi-byte
+             * operation, get the next byte, which is either the
+             * op code or a control character value.
+             */
+            op = echo_buf(ldata, tail + 1);
+
+            switch (op)
+            {
+                unsigned int num_chars = 0, num_bs = 0;
+
+            case ECHO_OP_ERASE_TAB:
+                num_chars = echo_buf(ldata, tail + 2);
+
+                /*
+                 * Determine how many columns to go back
+                 * in order to erase the tab.
+                 * This depends on the number of columns
+                 * used by other characters within the tab
+                 * area.  If this (modulo 8) count is from
+                 * the start of input rather than from a
+                 * previous tab, we offset by canon column.
+                 * Otherwise, tab spacing is normal.
+                 */
+                if (!(num_chars & 0x80))
+                {
+                    num_chars += ldata->canon_column;
+                }
+                num_bs = 8 - (num_chars & 7);
+
+                while (num_bs--)
+                {
+                    ch = '\b';
+                    rt_device_write((rt_device_t)tty, -1, &ch, 1);
+                    if (ldata->column > 0)
+                    {
+                        ldata->column--;
+                    }
+                }
+                tail += 3;
+                break;
+
+            case ECHO_OP_SET_CANON_COL:
+                ldata->canon_column = ldata->column;
+                tail += 2;
+                break;
+
+            case ECHO_OP_MOVE_BACK_COL:
+                if (ldata->column > 0)
+                {
+                    ldata->column--;
+                }
+                tail += 2;
+                break;
+
+            case ECHO_OP_START:
+                ch = ECHO_OP_START;
+                rt_device_write((rt_device_t)tty, -1, &ch, 1);
+                ldata->column++;
+                tail += 2;
+                break;
+
+            default:
+                /*
+                 * If the op is not a special byte code,
+                 * it is a ctrl char tagged to be echoed
+                 * as "^X" (where X is the letter
+                 * representing the control char).
+                 * Note that we must ensure there is
+                 * enough space for the whole ctrl pair.
+                 *
+                 */
+                ch = '^';
+                rt_device_write((rt_device_t)tty, -1, &ch, 1);
+                ch = op ^ 0100;
+                rt_device_write((rt_device_t)tty, -1, &ch, 1);
+                ldata->column += 2;
+                tail += 2;
+            }
+        }
+        else
+        {
+            if (O_OPOST(tty))
+            {
+                int retval = do_output_char(c, tty);
+                if (retval < 0)
+                {
+                    break;
+                }
+            }
+            else
+            {
+                rt_device_write((rt_device_t)tty, -1, &c, 1);
+            }
+            tail += 1;
+        }
+    }
+
+    /* If the echo buffer is nearly full (so that the possibility exists
+     * of echo overrun before the next commit), then discard enough
+     * data at the tail to prevent a subsequent overrun */
+    while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK)
+    {
+        if (echo_buf(ldata, tail) == ECHO_OP_START)
+        {
+            if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)
+            {
+                tail += 3;
+            }
+            else
+            {
+                tail += 2;
+            }
+        }
+        else
+        {
+            tail++;
+        }
+    }
+
+    ldata->echo_tail = tail;
+    return 0;
+}
+
+static void commit_echoes(struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    size_t nr = 0, old = 0;
+    size_t head = 0;
+    int level = 0;
+
+    head = ldata->echo_head;
+    ldata->echo_mark = head;
+    old = ldata->echo_commit - ldata->echo_tail;
+
+    /* Process committed echoes if the accumulated # of bytes
+     * is over the threshold (and try again each time another
+     * block is accumulated) */
+    nr = head - ldata->echo_tail;
+    if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
+    {
+        return;
+    }
+
+    level = rt_hw_interrupt_disable();
+    ldata->echo_commit = head;
+    __process_echoes(tty);
+    rt_hw_interrupt_enable(level);
+}
+
+static void process_echoes(struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    int level = 0;
+    if (ldata->echo_mark == ldata->echo_tail)
+    {
+        return;
+    }
+
+    level = rt_hw_interrupt_disable();
+    ldata->echo_commit = ldata->echo_mark;
+    __process_echoes(tty);
+    rt_hw_interrupt_enable(level);
+}
+
+/* NB: echo_mark and echo_head should be equivalent here */
+static void flush_echoes(struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    int level = 0;
+
+    if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
+        ldata->echo_commit == ldata->echo_head)
+    {
+        return;
+    }
+
+    level = rt_hw_interrupt_disable();
+    ldata->echo_commit = ldata->echo_head;
+    __process_echoes(tty);
+    rt_hw_interrupt_enable(level);
+}
+/**
+ *  n_tty_set_termios   -   termios data changed
+ *  @tty: terminal
+ *  @old: previous data
+ *
+ *  Called by the tty layer when the user changes termios flags so
+ *  that the line discipline can plan ahead. This function cannot sleep
+ *  and is protected from re-entry by the tty layer. The user is
+ *  guaranteed that this function will not be re-entered or in progress
+ *  when the ldisc is closed.
+ *
+ *  Locking: Caller holds tty->termios_rwsem
+ */
+
+static void n_tty_set_termios(struct tty_struct *tty, struct termios *old)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    if (!old || (old->c_lflag ^ tty->init_termios.c_lflag) & (ICANON | EXTPROC))
+    {
+        rt_memset(ldata->read_flags, 0, RT_TTY_BUF);
+        ldata->line_start = ldata->read_tail;
+        if (!L_ICANON(tty) || !read_cnt(ldata))
+        {
+            ldata->canon_head = ldata->read_tail;
+            ldata->push = 0;
+        }
+        else
+        {
+            set_bit((ldata->read_head - 1) & (RT_TTY_BUF - 1),(int *)ldata->read_flags);
+            ldata->canon_head = ldata->read_head;
+            ldata->push = 1;
+        }
+        ldata->commit_head = ldata->read_head;
+        ldata->erasing = 0;
+        ldata->lnext = 0;
+    }
+
+    ldata->icanon = (L_ICANON(tty) != 0);
+
+    if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
+        I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
+        I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
+        I_PARMRK(tty))
+    {
+        rt_memset(ldata->char_map, 0, 256);
+        if (I_IGNCR(tty) || I_ICRNL(tty))
+        {
+            set_bit('\r', (int *)ldata->char_map);
+        }
+
+        if (I_INLCR(tty))
+        {
+            set_bit('\n', (int *)ldata->char_map);
+        }
+
+        if (L_ICANON(tty))
+        {
+            set_bit(ERASE_CHAR(tty), (int *)ldata->char_map);
+            set_bit(KILL_CHAR(tty),(int *) ldata->char_map);
+            set_bit(EOF_CHAR(tty), (int *)ldata->char_map);
+            set_bit('\n',(int *) ldata->char_map);
+            set_bit(EOL_CHAR(tty),(int *) ldata->char_map);
+            if (L_IEXTEN(tty))
+            {
+                set_bit(WERASE_CHAR(tty), (int *)ldata->char_map);
+                set_bit(LNEXT_CHAR(tty), (int *)ldata->char_map);
+                set_bit(EOL2_CHAR(tty), (int *)ldata->char_map);
+                if (L_ECHO(tty))
+                {
+                    set_bit(REPRINT_CHAR(tty),
+                        (int *)ldata->char_map);
+                }
+            }
+        }
+        if (I_IXON(tty))
+        {
+            set_bit(START_CHAR(tty), (int *)ldata->char_map);
+            set_bit(STOP_CHAR(tty), (int *)ldata->char_map);
+        }
+        if (L_ISIG(tty))
+        {
+            set_bit(INTR_CHAR(tty), (int *)ldata->char_map);
+            set_bit(QUIT_CHAR(tty), (int *)ldata->char_map);
+            set_bit(SUSP_CHAR(tty), (int *)ldata->char_map);
+        }
+        clear_bit(__DISABLED_CHAR, (int *)ldata->char_map);
+        ldata->raw = 0;
+        ldata->real_raw = 0;
+    }
+    else
+    {
+        ldata->raw = 1;
+        if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
+            (I_IGNPAR(tty) || !I_INPCK(tty))/* &&
+            (tty->driver->flags & TTY_DRIVER_REAL_RAW)*/)
+        {
+            ldata->real_raw = 1;
+        }
+        else
+        {
+            ldata->real_raw = 0;
+        }
+    }
+}
+
+void console_ldata_init(struct tty_struct *tty)
+{
+    struct n_tty_data *ldata = RT_NULL;
+
+    ldata = rt_malloc(sizeof(struct n_tty_data));
+    if (ldata == RT_NULL)
+    {
+        LOG_E("console_ldata_init ldata malloc fail");
+        return;
+    }
+    tty->disc_data = ldata;
+    reset_buffer_flags(ldata);
+    ldata->column = 0;
+    ldata->canon_column = 0;
+    ldata->no_room = 0;
+    ldata->lnext = 0;
+    n_tty_set_termios(tty, RT_NULL);
+    return;
+}
+
+static int n_tty_open(struct dfs_fd *fd)
+{
+    int ret = 0;
+    struct n_tty_data *ldata = RT_NULL;
+    struct tty_struct *tty = (struct tty_struct*)fd->fnode->data;
+
+    ldata = rt_malloc(sizeof(struct n_tty_data));
+    if (ldata == RT_NULL)
+    {
+        LOG_E("n_tty_open ldata malloc fail");
+        return -1;
+    }
+
+    ldata->atomic_read_lock = rt_mutex_create("atomic_read_lock",RT_IPC_FLAG_FIFO);
+    ldata->output_lock = rt_mutex_create("output_lock",RT_IPC_FLAG_FIFO);
+    tty->disc_data = ldata;
+    reset_buffer_flags(ldata);
+    ldata->column = 0;
+    ldata->canon_column = 0;
+    ldata->lnext = 0;
+    n_tty_set_termios(tty, RT_NULL);
+    return ret;
+}
+
+static inline int input_available_p(struct tty_struct *tty, int poll)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
+
+    if (ldata->icanon && !L_EXTPROC(tty))
+    {
+        return ldata->canon_head != ldata->read_tail;
+    }
+    else
+    {
+        return ldata->commit_head - ldata->read_tail >= amt;
+    }
+}
+
+/**
+ *  copy_from_read_buf  -   copy read data directly
+ *  @tty: terminal device
+ *  @b: user data
+ *  @nr: size of data
+ *
+ *  Helper function to speed up n_tty_read.  It is only called when
+ *  ICANON is off; it copies characters straight from the tty queue to
+ *  user space directly.  It can be profitably called twice; once to
+ *  drain the space from the tail pointer to the (physical) end of the
+ *  buffer, and once to drain the space from the (physical) beginning of
+ *  the buffer to head pointer.
+ *
+ *  Called under the ldata->atomic_read_lock sem
+ *
+ *  n_tty_read()/consumer path:
+ *      caller holds non-exclusive termios_rwsem
+ *      read_tail published
+ */
+
+static int copy_from_read_buf(struct tty_struct *tty,char *b,size_t nr)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    size_t n = 0;
+    rt_bool_t is_eof = 0;
+    size_t head = ldata->commit_head;
+    size_t tail = ldata->read_tail & (RT_TTY_BUF - 1);
+
+    n = min(head - ldata->read_tail, RT_TTY_BUF - tail);
+    n = min(nr, n);
+    if (n)
+    {
+        const char *from = read_buf_addr(ldata, tail);
+        rt_memcpy(b, from, n);
+        is_eof = n == 1 && *from == EOF_CHAR(tty);
+        ldata->read_tail += n;
+        /* Turn single EOF into zero-length read */
+        if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
+            (head == ldata->read_tail))
+        {
+            n = 0;
+        }
+
+    }
+    return n;
+}
+
+/**
+ *  canon_copy_from_read_buf    -   copy read data in canonical mode
+ *  @tty: terminal device
+ *  @b: user data
+ *  @nr: size of data
+ *
+ *  Helper function for n_tty_read.  It is only called when ICANON is on;
+ *  it copies one line of input up to and including the line-delimiting
+ *  character into the user-space buffer.
+ *
+ *  NB: When termios is changed from non-canonical to canonical mode and
+ *  the read buffer contains data, n_tty_set_termios() simulates an EOF
+ *  push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
+ *  This causes data already processed as input to be immediately available
+ *  as input although a newline has not been received.
+ *
+ *  Called under the atomic_read_lock mutex
+ *
+ *  n_tty_read()/consumer path:
+ *      caller holds non-exclusive termios_rwsem
+ *      read_tail published
+ */
+
+static int canon_copy_from_read_buf(struct tty_struct *tty, char *b, size_t nr)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    size_t n = 0, size = 0, more = 0, c = 0;
+    size_t eol = 0;
+    size_t tail = 0;
+    int found = 0;
+
+    /* N.B. avoid overrun if nr == 0 */
+    if (nr == 0)
+    {
+        return 0;
+    }
+
+    n = min(nr + 1, ldata->canon_head - ldata->read_tail);
+
+    tail = ldata->read_tail & (RT_TTY_BUF - 1);
+    size = min(tail + n, RT_TTY_BUF);
+
+    eol = find_next_bit(ldata->read_flags, size, tail);
+    more = n - (size - tail);
+    if (eol == RT_TTY_BUF && more)
+    {
+        /* scan wrapped without finding set bit */
+        eol = find_next_bit(ldata->read_flags, more, 0);
+        found = eol != more;
+    }
+    else
+    {
+        found = eol != size;
+    }
+
+    n = eol - tail;
+    if (n > RT_TTY_BUF)
+    {
+        n += RT_TTY_BUF;
+    }
+    c = n + found;
+
+    if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
+    {
+        c = min(nr, c);
+        n = c;
+    }
+
+    size_t buf_size = RT_TTY_BUF - tail;
+    const void *from = read_buf_addr(ldata, tail);
+    if (n > buf_size)
+    {
+        rt_memcpy(b, from, buf_size);
+        b += buf_size;
+        n -= buf_size;
+        from = ldata->read_buf;
+    }
+    rt_memcpy(b, from, n);
+
+    if (found)
+    {
+        clear_bit(eol, (int *)ldata->read_flags);
+    }
+    ldata->read_tail = ldata->read_tail + c;
+
+    if (found)
+    {
+        if (!ldata->push)
+        {
+            ldata->line_start = ldata->read_tail;
+        }
+        else
+        {
+            ldata->push = 0;
+        }
+    }
+    return n;
+}
+
+
+static int n_tty_close(struct tty_struct *tty)
+{
+    int ret = 0;
+    struct n_tty_data *ldata = RT_NULL;
+    struct tty_struct *o_tty = RT_NULL;
+
+    RT_ASSERT(tty != RT_NULL);
+    if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+    {
+        o_tty = tty->other_struct;
+    }
+    else
+    {
+        o_tty = tty;
+    }
+
+    ldata = o_tty->disc_data;
+    rt_free(ldata);
+    o_tty->disc_data = RT_NULL;
+    return ret;
+}
+
+static int n_tty_ioctl(struct dfs_fd *fd, int cmd, void *args)
+{
+    int ret = 0;
+    struct tty_struct *real_tty = RT_NULL;
+    struct tty_struct *tty = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+    {
+        real_tty = tty->other_struct;
+    }
+    else
+    {
+        real_tty = tty;
+    }
+
+    switch(cmd)
+    {
+
+    default:
+        ret = n_tty_ioctl_extend(real_tty, cmd, args);
+        if (ret != -ENOIOCTLCMD)
+        {
+            return ret;
+        }
+    }
+
+    ret = rt_device_control((rt_device_t)real_tty, cmd, args);
+    if (ret != -ENOIOCTLCMD)
+    {
+        return ret;
+    }
+    return ret;
+}
+
+static void
+n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
+{
+    isig(signal, tty);
+    if (L_ECHO(tty))
+    {
+        echo_char(c, tty);
+        commit_echoes(tty);
+    }
+    else
+    {
+        process_echoes(tty);
+    }
+    return;
+}
+
+/**
+ *  n_tty_receive_char  -   perform processing
+ *  @tty: terminal device
+ *  @c: character
+ *
+ *  Process an individual character of input received from the driver.
+ *  This is serialized with respect to itself by the rules for the
+ *  driver above.
+ *
+ *  n_tty_receive_buf()/producer path:
+ *      caller holds non-exclusive termios_rwsem
+ *      publishes canon_head if canonical mode is active
+ *
+ *  Returns 1 if LNEXT was received, else returns 0
+ */
+
+static int n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    if (I_IXON(tty))
+    {
+        if (c == START_CHAR(tty)) /*ctrl + p realize missing*/
+        {
+            process_echoes(tty);
+            return 0;
+        }
+        if (c == STOP_CHAR(tty)) /*ctrl + s realize missing*/
+        {
+            return 0;
+        }
+    }
+
+    if (L_ISIG(tty))
+    {
+        if (c == INTR_CHAR(tty)) /*ctrl + c realize missing*/
+        {
+            n_tty_receive_signal_char(tty, SIGINT, c);
+            return 0;
+        }
+        else if (c == QUIT_CHAR(tty)) /*ctrl + d realize missing*/
+        {
+            n_tty_receive_signal_char(tty, SIGQUIT, c);
+            return 0;
+        }
+        else if (c == SUSP_CHAR(tty)) /*ctrl + z realize missing*/
+        {
+            n_tty_receive_signal_char(tty, SIGTSTP, c);
+            return 0;
+        }
+    }
+
+    if (c == '\r')
+    {
+        if (I_IGNCR(tty))
+        {
+            return 0;
+        }
+
+        if (I_ICRNL(tty))
+        {
+            c = '\n';
+        }
+    }
+    else if (c == '\n' && I_INLCR(tty))
+    {
+        c = '\r';
+    }
+
+    if (ldata->icanon)
+    {
+        if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
+            (c == WERASE_CHAR(tty) && L_IEXTEN(tty)))
+        {
+            eraser(c, tty);
+            commit_echoes(tty);
+            return 0;
+        }
+        if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty))
+        {
+            ldata->lnext = 1;
+            if (L_ECHO(tty))
+            {
+                finish_erasing(ldata);
+                if (L_ECHOCTL(tty))
+                {
+                    echo_char_raw('^', ldata);
+                    echo_char_raw('\b', ldata);
+                    commit_echoes(tty);
+                }
+            }
+            return 1;
+        }
+        if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty))
+        {
+            size_t tail = ldata->canon_head;
+
+            finish_erasing(ldata);
+            echo_char(c, tty);
+            echo_char_raw('\n', ldata);
+            while (tail != ldata->read_head)
+            {
+                echo_char(read_buf(ldata, tail), tty);
+                tail++;
+            }
+            commit_echoes(tty);
+            return 0;
+        }
+        if (c == '\n')
+        {
+            if (L_ECHO(tty) || L_ECHONL(tty))
+            {
+                echo_char_raw('\n', ldata);
+                commit_echoes(tty);
+            }
+            goto handle_newline;
+        }
+        if (c == EOF_CHAR(tty))
+        {
+            c = __DISABLED_CHAR;
+            goto handle_newline;
+        }
+        if ((c == EOL_CHAR(tty)) ||
+            (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))
+        {
+            /*
+             * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
+             */
+            if (L_ECHO(tty))
+            {
+                /* Record the column of first canon char. */
+                if (ldata->canon_head == ldata->read_head)
+                {
+                    echo_set_canon_col(ldata);
+                }
+
+                echo_char(c, tty);
+                commit_echoes(tty);
+            }
+            /*
+             * XXX does PARMRK doubling happen for
+             * EOL_CHAR and EOL2_CHAR?
+             */
+            if (c == (unsigned char) '\377' && I_PARMRK(tty))
+            {
+                put_tty_queue(c, ldata);
+            }
+
+handle_newline:
+            set_bit(ldata->read_head & (RT_TTY_BUF - 1), (int *)ldata->read_flags);
+            put_tty_queue(c, ldata);
+            ldata->canon_head = ldata->read_head;
+            tty_wakeup_check(tty);
+            return 0;
+        }
+    }
+
+    if (L_ECHO(tty))
+    {
+        finish_erasing(ldata);
+        if (c == '\n')
+        {
+            echo_char_raw('\n', ldata);
+        }
+        else
+        {
+            /* Record the column of first canon char. */
+            if (ldata->canon_head == ldata->read_head)
+            {
+                echo_set_canon_col(ldata);
+            }
+            echo_char(c, tty);
+        }
+        commit_echoes(tty);
+    }
+
+    /* PARMRK doubling check */
+    if (c == (unsigned char) '\377' && I_PARMRK(tty))
+    {
+        put_tty_queue(c, ldata);
+    }
+
+    put_tty_queue(c, ldata);
+    return 0;
+}
+
+static inline void n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    if (L_ECHO(tty))
+    {
+        finish_erasing(ldata);
+        /* Record the column of first canon char. */
+        if (ldata->canon_head == ldata->read_head)
+        {
+            echo_set_canon_col(ldata);
+        }
+
+        echo_char(c, tty);
+        commit_echoes(tty);
+    }
+    /* PARMRK doubling check */
+    if (c == (unsigned char) '\377' && I_PARMRK(tty))
+    {
+        put_tty_queue(c, ldata);
+    }
+
+    put_tty_queue(c, ldata);
+}
+
+static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+{
+    n_tty_receive_char_inline(tty, c);
+}
+
+static void n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    ldata->lnext = 0;
+    if (flag == TTY_NORMAL)
+    {
+        if (I_ISTRIP(tty))
+        {
+            c &= 0x7f;
+        }
+
+        if (I_IUCLC(tty) && L_IEXTEN(tty))
+        {
+            c = tolower(c);
+        }
+
+        n_tty_receive_char(tty, c);
+    }
+    else
+    {
+        //n_tty_receive_char_flagged(tty, c, flag);
+    }
+
+}
+
+static void n_tty_receive_buf_real_raw(struct tty_struct *tty, char *cp, int count)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    size_t n = 0, head = 0;
+
+    head = ldata->read_head & (RT_TTY_BUF - 1);
+    n = min(count, RT_TTY_BUF - head);
+    rt_memcpy(read_buf_addr(ldata, head), cp, n);
+    ldata->read_head += n;
+    cp += n;
+    count -= n;
+
+    head = ldata->read_head & (RT_TTY_BUF - 1);
+    n = min(count, RT_TTY_BUF - head);
+    rt_memcpy(read_buf_addr(ldata, head), cp, n);
+    ldata->read_head += n;
+}
+
+static void n_tty_receive_buf_raw(struct tty_struct *tty, char *cp, int count)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    char flag = TTY_NORMAL;
+
+    while (count--)
+    {
+        if (flag == TTY_NORMAL)
+        {
+            put_tty_queue(*cp++, ldata);
+        }
+    }
+}
+
+static void n_tty_receive_buf_standard(struct tty_struct *tty, char *cp, int count)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    char flag = TTY_NORMAL;
+
+    while (count--)
+    {
+        char c = *cp++;
+
+        if (I_ISTRIP(tty))
+        {
+            c &= 0x7f;
+        }
+
+        if (I_IUCLC(tty) && L_IEXTEN(tty))
+        {
+            c = tolower(c);
+        }
+
+        if (L_EXTPROC(tty))
+        {
+            put_tty_queue(c, ldata);
+            continue;
+        }
+
+        if (!test_bit(c, (int *)ldata->char_map))
+        {
+            n_tty_receive_char_inline(tty, c);
+        }
+        else if (n_tty_receive_char_special(tty, c) && count)
+        {
+            n_tty_receive_char_lnext(tty, *cp++, flag);
+            count--;
+        }
+    }
+}
+
+static inline void n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+
+    if (L_ECHO(tty))
+    {
+        finish_erasing(ldata);
+        /* Record the column of first canon char. */
+        if (ldata->canon_head == ldata->read_head)
+        {
+            echo_set_canon_col(ldata);
+        }
+
+        echo_char(c, tty);
+        commit_echoes(tty);
+    }
+    put_tty_queue(c, ldata);
+}
+
+static void n_tty_receive_buf_fast(struct tty_struct *tty, char *cp, int count)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    char flag = TTY_NORMAL;
+
+    while (count--)
+    {
+        unsigned char c = *cp++;
+
+        if (!test_bit(c, (int *)ldata->char_map))
+        {
+            n_tty_receive_char_fast(tty, c);
+        }
+        else if (n_tty_receive_char_special(tty, c) && count)
+        {
+            n_tty_receive_char_lnext(tty, *cp++, flag);
+            count--;
+        }
+    }
+}
+
+static void __receive_buf(struct tty_struct *tty, char *cp, int count)
+{
+    struct n_tty_data *ldata = tty->disc_data;
+    rt_bool_t preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
+
+    if (ldata->real_raw)
+    {
+        n_tty_receive_buf_real_raw(tty, cp, count);
+    }
+
+    else if (ldata->raw || (L_EXTPROC(tty) && !preops))
+    {
+        n_tty_receive_buf_raw(tty, cp, count);
+    }
+    else
+    {
+        if (!preops && !I_PARMRK(tty))
+        {
+            n_tty_receive_buf_fast(tty, cp, count);
+        }
+        else
+        {
+            n_tty_receive_buf_standard(tty, cp, count);
+        }
+        flush_echoes(tty);
+    }
+
+    if (ldata->icanon && !L_EXTPROC(tty))
+        return;
+
+    /* publish read_head to consumer */
+    ldata->commit_head = ldata->read_head;
+
+    if (read_cnt(ldata))
+    {
+        tty_wakeup_check(tty);
+    }
+}
+
+int n_tty_receive_buf(struct tty_struct *tty,char *cp, int count)
+{
+    int size = 0;
+    struct n_tty_data *ldata = tty->disc_data;
+    int room = 0, n = 0, rcvd = 0, overflow = 0;
+
+    size = count;
+    while(1)
+    {
+        size_t tail = ldata->read_tail;
+
+        room = RT_TTY_BUF - (ldata->read_head - tail);
+
+        if (I_PARMRK(tty))
+        {
+            room = (room +2)/3;
+        }
+        room--;
+        if (room <= 0)
+        {
+            overflow = ldata->icanon && ldata->canon_head == tail;
+            if (overflow && room < 0)
+            {
+                ldata->read_head--;
+            }
+
+            room = overflow;
+        }
+        else
+        {
+            overflow = 0;
+        }
+
+        n =  min(size, room);
+
+        if (!n)
+        {
+            break;
+        }
+
+        if (!overflow)
+        {
+            __receive_buf(tty, cp, n);
+        }
+
+        cp += n;
+        size -= n;
+        rcvd += n;
+    }
+    return count - size;
+}
+
+/**
+ *  job_control     -   check job control
+ *  @tty: tty
+ *  @file: file handle
+ *
+ *  Perform job control management checks on this file/tty descriptor
+ *  and if appropriate send any needed signals and return a negative
+ *  error code if action should be taken.
+ *
+ *  Locking: redirected write test is safe
+ *       current->signal->tty check is safe
+ *       ctrl_lock to safely reference tty->pgrp
+ */
+
+static int job_control(struct tty_struct *tty)
+{
+    return __tty_check_change(tty, SIGTTIN);
+}
+
+static int n_tty_read(struct dfs_fd *fd, void *buf, size_t count)
+{
+    int level = 0;
+    char *b = (char *)buf;
+    struct tty_struct *tty = RT_NULL;
+    struct rt_lwp *lwp = RT_NULL;
+    struct rt_wqueue *wq = RT_NULL;
+    int wait_ret = 0;
+    int retval = 0;
+    int c = 0;
+
+    level = rt_hw_interrupt_disable();
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    c = job_control(tty);
+    if (c < 0)
+    {
+        return c;
+    }
+
+    struct n_tty_data *ldata = tty->disc_data;
+
+    lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
+    wq = wait_queue_get(lwp, tty);
+
+    while(count)
+    {
+        if ((!input_available_p(tty, 0)))
+        {
+            if (fd->flags & O_NONBLOCK)
+            {
+                retval = -EAGAIN;
+                break;
+            }
+
+            wait_ret = rt_wqueue_wait_interruptible(wq, 0, RT_WAITING_FOREVER);
+            if (wait_ret != 0)
+            {
+                break;
+            }
+        }
+
+        if (ldata->icanon && !L_EXTPROC(tty))
+        {
+            retval = canon_copy_from_read_buf(tty, b, count);
+        }
+        else
+        {
+            retval = copy_from_read_buf(tty, b, count);
+        }
+
+        if (retval >= 1)
+        {
+            break;
+        }
+    }
+    rt_hw_interrupt_enable(level);
+    return retval;
+}
+
+static int n_tty_write(struct dfs_fd *fd, const void *buf, size_t count)
+{
+    int retval = 0;
+    char *b = (char *)buf;
+    int c = 0;
+    struct tty_struct *tty = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    retval = tty_check_change(tty);
+    if (retval)
+    {
+        return retval;
+    }
+
+    process_echoes(tty);
+    retval = count;
+    while(1)
+    {
+        if (O_OPOST(tty))
+        {
+            while (count > 0)
+            {
+                ssize_t num = process_output_block(tty, b, count);
+                if (num < 0)
+                {
+                    if (num == -EAGAIN)
+                    {
+                        break;
+                    }
+
+                    retval = num;
+                    goto break_out;
+                }
+                b += num;
+                count -= num;
+                if (count == 0)
+                {
+                    break;
+                }
+
+                c = *b;
+                if (process_output(c, tty) < 0)
+                {
+                    break;
+                }
+
+                b++;
+                count--;
+            }
+            retval -= count;
+        }
+        else
+        {
+            int level = 0;
+            while (count > 0)
+            {
+                level = rt_hw_interrupt_disable();
+                c = rt_device_write((rt_device_t)tty, -1, b, count);
+                rt_hw_interrupt_enable(level);
+                if (c < 0)
+                {
+                    retval = c;
+                    goto break_out;
+                }
+                b += c;
+                count -= c;
+            }
+            retval -= count;
+        }
+
+        if (!count)
+        {
+            break;
+        }
+        if (fd->flags & O_NONBLOCK)
+        {
+            break;
+        }
+    }
+break_out:
+    return retval;
+}
+
+static int n_tty_flush(struct dfs_fd *fd)
+{
+    return 0;
+}
+
+static int n_tty_lseek(struct dfs_fd *fd, off_t offset)
+{
+    return 0;
+}
+
+static int n_tty_getdents(struct dfs_fd *fd, struct dirent *dirp, uint32_t count)
+{
+    return 0;
+}
+
+static int n_tty_poll(struct dfs_fd *fd, struct rt_pollreq *req)
+{
+    rt_base_t level = 0;
+    int mask = POLLOUT;
+    struct tty_struct *tty = RT_NULL;
+    struct rt_wqueue *wq = RT_NULL;
+    struct rt_lwp *lwp = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+
+    RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
+
+    lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
+    wq = wait_queue_get(lwp, tty);
+    rt_poll_add(wq, req);
+    level = rt_hw_interrupt_disable();
+
+    if (input_available_p(tty, 1))
+    {
+        mask |= POLLIN;
+    }
+
+    rt_hw_interrupt_enable(level);
+
+    return mask;
+}
+
+static struct tty_ldisc_ops n_tty_ops = {
+    "n_tty",
+    0,
+    n_tty_open,
+    n_tty_close,
+    n_tty_ioctl,
+    n_tty_read,
+    n_tty_write,
+    n_tty_flush,
+    n_tty_lseek,
+    n_tty_getdents,
+    n_tty_poll,
+    n_tty_set_termios,
+    n_tty_receive_buf,
+    0,
+};
+
+void n_tty_init(void)
+{
+    tty_register_ldisc(N_TTY, &n_tty_ops);
+}

+ 7 - 6
components/libc/termios/posix_termios.c → components/drivers/tty/posix_termios.c

@@ -1,23 +1,24 @@
 /*
- * Copyright (c) 2006-2018, RT-Thread Development Team
+ * Copyright (c) 2006-2021, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Change Logs:
  * Date           Author       Notes
  * 2017/08/30     Bernard      The first version
+ * 2021/12/10     linzhenxing  put tty system
  */
 #include <stdlib.h>
 #include <string.h>
 #include <rtthread.h>
 #include <dfs_posix.h>
 
-#include <termios.h>
+#include <posix_termios.h>
 
 int tcgetattr(int fd, struct termios *tio)
 {
     /* Get the current serial port settings. */
-    if (ioctl(fd, TCGETA, tio))
+    if (ioctl(fd, TCGETS, tio))
         return -1;
 
     return 0;
@@ -29,19 +30,19 @@ int tcsetattr(int fd, int act, const struct termios *tio)
     {
     case TCSANOW:
         /* make the change immediately */
-        return (ioctl(fd, TCSETA, (void*)tio));
+        return (ioctl(fd, TCSETS, (void*)tio));
     case TCSADRAIN:
         /*
          * Don't make the change until all currently written data
          * has been transmitted.
          */
-        return (ioctl(fd, TCSETAW, (void*)tio));
+        return (ioctl(fd, TCSETSW, (void*)tio));
     case TCSAFLUSH:
         /* Don't make the change until all currently written data
          * has been transmitted, at which point any received but
          * unread data is also discarded.
          */
-        return (ioctl(fd, TCSETAF, (void*)tio));
+        return (ioctl(fd, TCSETSF, (void*)tio));
     default:
         errno = EINVAL;
         return (-1);

+ 368 - 0
components/drivers/tty/pty.c

@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#include <rtthread.h>
+#include <tty.h>
+#include <tty_ldisc.h>
+
+#define DBG_TAG               "PTY"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL               DBG_LOG
+#else
+#define DBG_LVL               DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+#define PTY_PTS_SIZE 10
+static struct tty_struct ptm_driver;
+static struct tty_struct pts_drivers[PTY_PTS_SIZE];
+static int pts_index = 0;
+
+static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index);
+
+/* check free pts device */
+static struct tty_struct *find_freepts(void)
+{
+    for(int i = 0; i < PTY_PTS_SIZE; i++)
+    {
+        if (pts_drivers[i].init_flag == TTY_INIT_FLAG_NONE)
+        {
+            pts_drivers[i].init_flag = TTY_INIT_FLAG_ALLOCED;
+            return &pts_drivers[i];
+        }
+    }
+    return RT_NULL;
+}
+
+/* Set the lock flag on a pty */
+static int pty_set_lock(struct tty_struct *tty, int *arg)
+{
+    int val = *arg;
+
+    if (val)
+    {
+        tty->pts_lock = val;
+    }
+    else
+    {
+        tty->pts_lock = val;
+    }
+    return 0;
+}
+
+static int pty_get_lock(struct tty_struct *tty, int *arg)
+{
+    *arg = tty->pts_lock;
+    return 0;
+}
+
+static int pty_get_index(struct tty_struct *tty, int *arg)
+{
+    *arg = tty->index;
+    return 0;
+}
+/* RT-Thread Device Interface */
+/*
+ * This function initializes console device.
+ */
+static rt_err_t pty_device_init(struct rt_device *dev)
+{
+    rt_err_t result = RT_EOK;
+    int level = 0;
+    struct tty_struct *tty = RT_NULL;
+    RT_ASSERT(dev != RT_NULL);
+
+    tty = (struct tty_struct *)dev;
+    level = rt_hw_interrupt_disable();
+    RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_REGED);
+    tty->init_flag = TTY_INIT_FLAG_INITED;
+    rt_hw_interrupt_enable(level);
+    return result;
+}
+
+static rt_err_t pty_device_open(struct rt_device *dev, rt_uint16_t oflag)
+{
+    rt_err_t result = RT_EOK;
+    return result;
+}
+
+static rt_err_t pty_device_close(struct rt_device *dev)
+{
+    rt_err_t result = RT_EOK;
+    struct tty_struct *tty = (struct tty_struct*)dev;
+    struct tty_struct *to = RT_NULL;
+
+    if (tty->subtype == PTY_TYPE_MASTER)
+    {
+        // to = tty->other_struct;
+        // to->init_flag = TTY_INIT_FLAG_NONE;
+        // to->other_struct = RT_NULL;
+        // to->foreground = RT_NULL;
+        // to->index = -1;
+        // tty_ldisc_kill(to);
+        // tty->other_struct = RT_NULL;
+    }
+    else
+    {
+        // to = tty->other_struct;
+        // to->other_struct = RT_NULL;
+        // tty->init_flag = TTY_INIT_FLAG_NONE;
+        // tty->other_struct = RT_NULL;
+        // tty->foreground = RT_NULL;
+        // tty->index = -1;
+        // tty->other_struct = RT_NULL;
+        // tty_ldisc_kill(tty);
+    }
+
+    return result;
+}
+
+static rt_size_t pty_device_read(struct rt_device *dev,
+        rt_off_t          pos,
+        void             *buffer,
+        rt_size_t         size)
+{
+    rt_size_t len = 0;
+
+    return len;
+}
+
+static rt_size_t pty_device_write(struct rt_device *dev,
+        rt_off_t          pos,
+        const void       *buffer,
+        rt_size_t         size)
+{
+    rt_base_t level = 0;
+    rt_size_t len = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_struct *to = RT_NULL;
+
+    tty = (struct tty_struct *)dev;
+    RT_ASSERT(tty != RT_NULL);
+    RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
+    to = tty->other_struct;
+    level = rt_hw_interrupt_disable();
+
+    if (to->ldisc->ops->receive_buf)
+    {
+        len = to->ldisc->ops->receive_buf(to, (char *)buffer, size);
+    }
+    rt_hw_interrupt_enable(level);
+
+    return len;
+}
+
+static rt_err_t  pty_device_control(rt_device_t dev, int cmd, void *args)
+{
+    struct tty_struct *tty = (struct tty_struct *)dev;
+
+    switch (cmd)
+    {
+    case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+        return pty_set_lock(tty, (int *)args);
+    case TIOCGPTLCK: /* Get PT Lock status */
+        return pty_get_lock(tty, (int *)args);
+    case TIOCGPTN: /* Get PT Number */
+        return pty_get_index(tty, (int *)args);
+    }
+
+    return -ENOIOCTLCMD;
+}
+
+static int ptmx_open(struct dfs_fd *fd)
+{
+    int ret = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_struct *pts_drv = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+    struct rt_lwp *lwp = RT_NULL;
+    struct rt_wqueue *wq = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+
+    pts_drv = find_freepts();
+    if (pts_drv == RT_NULL)
+    {
+        LOG_E("free pts driver find fail\n");
+        return -1;
+    }
+    ret = pts_register(tty, pts_drv, pts_index);
+    if (ret < 0)
+    {
+        LOG_E("pts register fail\n");
+        rt_free(pts_drv);
+        return -1;
+    }
+    pts_index++;
+    lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
+    wq = wait_queue_get(lwp, tty);
+    pts_drv->wait_queue = *wq;
+    tty->other_struct = pts_drv;
+    ld = tty->ldisc;
+    if (ld->ops->open)
+    {
+        ret = ld->ops->open(fd);
+    }
+
+    return ret;
+}
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops pty_device_ops =
+{
+    pty_device_init,
+    pty_device_open,
+    pty_device_close,
+    pty_device_read,
+    pty_device_write,
+    pty_device_control,
+};
+#endif /* RT_USING_DEVICE_OPS */
+static struct dfs_file_ops pts_fops;
+static struct dfs_file_ops ptmx_fops;
+static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index)
+{
+    rt_err_t ret = RT_EOK;
+    rt_base_t level = 0;
+    struct rt_device *device = RT_NULL;
+    char name[20];
+
+    RT_ASSERT(ptm_drv!=RT_NULL);
+    level = rt_hw_interrupt_disable();
+
+    if (pts_drv->init_flag != TTY_INIT_FLAG_ALLOCED)
+    {
+        LOG_E("pts%d has been registered\n", pts_index);
+        ret = (-RT_EBUSY);
+        goto _exit;
+    }
+
+    device = &pts_drv->parent;
+    device->type    = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+    device->ops     = &pty_device_ops;
+#else
+    device->init    = pty_device_init;
+    device->open    = pty_device_open;
+    device->close   = pty_device_close;
+    device->read    = pty_device_read;
+    device->write   = pty_device_write;
+    device->control = pty_device_control;
+#endif /* RT_USING_DEVICE_OPS */
+
+    rt_snprintf(name, sizeof(name), "pts%d", pts_index);
+    ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        LOG_E("pts%d register failed\n", pts_index);
+        ret = -RT_EIO;
+        goto _exit;
+    }
+
+#ifdef RT_USING_POSIX
+    /* set fops */
+    tty_set_fops(&pts_fops);
+    device->fops = &pts_fops;
+#endif
+
+    pts_drv->type = TTY_DRIVER_TYPE_PTY;
+    pts_drv->subtype = PTY_TYPE_SLAVE;
+
+    pts_drv->pgrp = -1;
+    pts_drv->session = -1;
+    pts_drv->foreground = RT_NULL;
+    pts_drv->index = pts_index;
+    pts_drv->pts_lock = 1;
+    rt_wqueue_init(&pts_drv->wait_queue);
+
+    tty_ldisc_init(pts_drv);
+
+extern struct termios tty_std_termios;
+    pts_drv->init_termios = tty_std_termios;
+    pts_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
+    pts_drv->init_termios.c_lflag |= ICANON;
+    pts_drv->init_termios.__c_ispeed = 38400;
+    pts_drv->init_termios.__c_ospeed = 38400;
+
+    pts_drv->other_struct = ptm_drv;
+
+    pts_drv->init_flag = TTY_INIT_FLAG_REGED;
+_exit:
+    rt_hw_interrupt_enable(level);
+
+    return ret;
+}
+
+static int ptmx_register(void)
+{
+    rt_base_t level = 0;
+    rt_err_t ret = RT_EOK;
+    struct rt_device *device = RT_NULL;
+    struct tty_struct *ptm_drv = &ptm_driver;
+
+    level = rt_hw_interrupt_disable();
+    RT_ASSERT(ptm_drv->init_flag == TTY_INIT_FLAG_NONE);
+
+    level = rt_hw_interrupt_disable();
+    device = &(ptm_drv->parent);
+
+    device->type = RT_Device_Class_Char;
+
+#ifdef RT_USING_DEVICE_OPS
+    device->ops     = &pty_device_ops;
+#else
+    device->init    = pty_device_init;
+    device->open    = pty_device_open;
+    device->close   = pty_device_close;
+    device->read    = pty_device_read;
+    device->write   = pty_device_write;
+    device->control = pty_device_control;
+#endif /* RT_USING_DEVICE_OPS */
+
+    ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        LOG_E("ptmx register fail\n");
+        ret = -RT_EIO;
+        goto _exit;
+    }
+
+#ifdef RT_USING_POSIX
+    /* set fops */
+    tty_set_fops(&ptmx_fops);
+    ptmx_fops.open = ptmx_open;
+    device->fops = &ptmx_fops;
+#endif
+
+    ptm_drv->type = TTY_DRIVER_TYPE_PTY;
+    ptm_drv->subtype = PTY_TYPE_MASTER;
+
+    ptm_drv->pgrp = -1;
+    ptm_drv->session = -1;
+    ptm_drv->foreground = RT_NULL;
+    rt_wqueue_init(&ptm_drv->wait_queue);
+
+    tty_ldisc_init(ptm_drv);
+
+extern struct termios tty_std_termios;
+    ptm_drv->init_termios.c_iflag = 0;
+    ptm_drv->init_termios.c_oflag = 0;
+    ptm_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
+    ptm_drv->init_termios.c_lflag = 0;
+    ptm_drv->init_termios.__c_ispeed = 38400;
+    ptm_drv->init_termios.__c_ospeed = 38400;
+
+    ptm_drv->init_flag = TTY_INIT_FLAG_REGED;
+
+_exit:
+    rt_hw_interrupt_enable(level);
+
+    return ret;
+}
+INIT_DEVICE_EXPORT(ptmx_register);

+ 335 - 0
components/drivers/tty/tty.c

@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021.12.07     linzhenxing      first version
+ */
+#include <dfs_file.h>
+#include <dfs_fs.h>
+#include <lwp.h>
+#include <rtdevice.h>
+#include <rtthread.h>
+#include <tty.h>
+#include <tty_ldisc.h>
+#if defined(RT_USING_POSIX)
+#include <posix_termios.h>
+#endif
+
+#define DBG_TAG               "TTY"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL               DBG_LOG
+#else
+#define DBG_LVL               DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+struct termios tty_std_termios = {  /* for the benefit of tty drivers  */
+    .c_iflag = IMAXBEL | IUCLC | INLCR | ICRNL | IGNPAR,
+    .c_oflag = OPOST,
+    .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+    .c_lflag = ISIG | ECHOE  | TOSTOP | NOFLSH,
+    RT_NULL,/* .c_line = N_TTY, */
+    .c_cc = INIT_C_CC,
+    .__c_ispeed = 38400,
+    .__c_ospeed = 38400
+};
+
+rt_inline int tty_sigismember(lwp_sigset_t *set, int _sig)
+{
+    unsigned long sig = _sig - 1;
+
+    if (_LWP_NSIG_WORDS == 1)
+    {
+        return 1 & (set->sig[0] >> sig);
+    }
+    else
+    {
+        return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
+    }
+}
+
+static int is_ignored(int sig)
+{
+    return (tty_sigismember(&current->signal, sig) ||
+        current->signal_handler[sig-1] == SIG_IGN);
+}
+
+/**
+ *  tty_check_change    -   check for POSIX terminal changes
+ *  @tty: tty to check
+ *
+ *  If we try to write to, or set the state of, a terminal and we're
+ *  not in the foreground, send a SIGTTOU.  If the signal is blocked or
+ *  ignored, go ahead and perform the operation.  (POSIX 7.2)
+ *
+ *  Locking: ctrl_lock
+ */
+
+int __tty_check_change(struct tty_struct *tty, int sig)
+{
+    unsigned long flags = 0;
+    pid_t pgrp = 0, tty_pgrp = 0;
+    struct rt_lwp *lwp = tty->foreground;
+    int ret = 0;
+    int level = 0;
+
+    level = rt_hw_interrupt_disable();
+    if (current == RT_NULL)
+    {
+        return 0;
+    }
+
+    if (current->tty != tty)
+    {
+        return 0;
+    }
+
+    pgrp = current->__pgrp;
+    tty_pgrp = tty->pgrp;
+
+    if (tty_pgrp && pgrp != tty->pgrp)
+    {
+        if (is_ignored(sig))
+        {
+            if (sig == SIGTTIN)
+            {
+                ret = -EIO;
+            }
+        }
+        else
+        {
+            if (lwp)
+            {
+                lwp_kill(lwp_to_pid(lwp), sig);
+            }
+        }
+    }
+    rt_hw_interrupt_enable(level);
+
+    if (!tty_pgrp)
+    {
+        LOG_D(tty, "sig=%d, tty->pgrp == -1!\n", sig);
+    }
+    return ret;
+}
+
+int tty_check_change(struct tty_struct *tty)
+{
+    return __tty_check_change(tty, SIGTTOU);
+}
+
+static int tty_open(struct dfs_fd *fd)
+{
+    int ret = 0;
+    int noctty = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    ld = tty->ldisc;
+    if (ld->ops->open)
+    {
+        ret = ld->ops->open(fd);
+    }
+    noctty = (fd->flags & O_NOCTTY);
+
+    rt_device_t device = (rt_device_t)fd->fnode->data;
+    if (fd->fnode->ref_count == 1)
+    {
+        ret = rt_device_open(device, fd->flags);
+    }
+    if (current == RT_NULL) //kernel mode not lwp
+    {
+        return ret;
+    }
+
+    if (!noctty &&
+        current->leader &&
+        !current->tty &&
+        tty->session == -1)
+    {
+        current->tty = tty;
+        current->tty_old_pgrp = 0;
+        tty->session = current->session;
+        tty->pgrp = current->__pgrp;
+        tty->foreground = current;
+    }
+
+    return ret;
+}
+
+static int tty_close(struct dfs_fd *fd)
+{
+    int ret = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    ld = tty->ldisc;
+    if (ld->ops->close)
+    {
+        //ld->ops->close(tty);
+    }
+    if (fd->fnode->ref_count == 1)
+    {
+        ret = rt_device_close((rt_device_t)tty);
+    }
+    return ret;
+}
+
+static int tiocsctty(struct tty_struct *tty, int arg)
+{
+    if (current->leader &&
+        (current->session == tty->session))
+    {
+        return 0;        
+    }
+
+    /*
+     * The process must be a session leader and
+     * not have a controlling tty already.
+     */
+    if (!current->leader || current->tty)
+    {
+        return -EPERM;        
+    }
+
+    if (tty->session > 0)
+    {
+        LOG_E("this tty have control process\n");
+
+    }
+    current->tty = tty;
+    current->tty_old_pgrp = 0;
+    tty->session = current->session;
+    tty->pgrp = current->__pgrp;
+    tty->foreground = current;
+    if (tty->type == TTY_DRIVER_TYPE_PTY)
+    {
+        tty->other_struct->foreground = current;
+    }
+    return 0;
+}
+
+static int tty_ioctl(struct dfs_fd *fd, int cmd, void *args)
+{
+    int ret = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_struct *real_tty = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+
+    if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+    {
+        real_tty = tty->other_struct;
+    }
+    else
+    {
+        real_tty = tty;
+    }
+    switch (cmd)
+    {
+    case TIOCSCTTY:
+        return tiocsctty(real_tty, 1);
+    }
+    ld = tty->ldisc;
+    if (ld->ops->ioctl)
+    {
+        ret = ld->ops->ioctl(fd, cmd, args);
+    }
+    return ret;
+}
+
+static int tty_read(struct dfs_fd *fd, void *buf, size_t count)
+{
+    int ret = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    ld = tty->ldisc;
+    if (ld->ops->read)
+    {
+        ret = ld->ops->read(fd, buf, count);
+    }
+    return ret;
+}
+
+static int tty_write(struct dfs_fd *fd, const void *buf, size_t count)
+{
+    int ret = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    ld = tty->ldisc;
+    if (ld->ops->write)
+    {
+        ret = ld->ops->write(fd, buf, count);
+    }
+    return ret;
+}
+
+static int tty_poll(struct dfs_fd *fd, struct rt_pollreq *req)
+{
+    int ret = 0;
+    struct tty_struct *tty = RT_NULL;
+    struct tty_ldisc *ld = RT_NULL;
+
+    tty = (struct tty_struct *)fd->fnode->data;
+    RT_ASSERT(tty != RT_NULL);
+    ld = tty->ldisc;
+    if (ld->ops->poll)
+    {
+        ret = ld->ops->poll(fd, req);
+    }
+    return ret;
+}
+
+static const struct dfs_file_ops tty_fops =
+{
+    tty_open,
+    tty_close,
+    tty_ioctl,
+    tty_read,
+    tty_write,
+    RT_NULL, /* flush */
+    RT_NULL, /* lseek */
+    RT_NULL, /* getdents */
+    tty_poll,
+};
+static const struct dfs_file_ops console_fops =
+{
+    tty_open,
+    tty_close,
+    tty_ioctl,
+    tty_read,
+    tty_write,
+    RT_NULL, /* flush */
+    RT_NULL, /* lseek */
+    RT_NULL, /* getdents */
+    tty_poll,
+};
+
+void console_init()
+{
+    n_tty_init();
+}
+
+void tty_set_fops(struct dfs_file_ops *fops)
+{
+    *fops = tty_fops;
+}
+
+void console_set_fops(struct dfs_file_ops *fops)
+{
+    *fops = console_fops;
+}

+ 108 - 0
components/drivers/tty/tty_ioctl.c

@@ -0,0 +1,108 @@
+#include <stddef.h>
+#include <rtthread.h>
+#include <tty.h>
+#if defined(RT_USING_POSIX)
+#include <posix_termios.h>
+#endif
+
+#define DBG_TAG               "TTY_IOCTL"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL               DBG_LOG
+#else
+#define DBG_LVL               DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+/*
+ * Internal flag options for termios setting behavior
+ */
+#define TERMIOS_FLUSH   1
+#define TERMIOS_WAIT    2
+#define TERMIOS_TERMIO  4
+#define TERMIOS_OLD 8
+
+/**
+ *  set_termios     -   set termios values for a tty
+ *  @tty: terminal device
+ *  @arg: user data
+ *  @opt: option information
+ *
+ *  Helper function to prepare termios data and run necessary other
+ *  functions before using tty_set_termios to do the actual changes.
+ *
+ *  Locking:
+ *      Called functions take ldisc and termios_rwsem locks
+ */
+
+static int set_termios(struct tty_struct *tty, void *arg, int opt)
+{
+    struct termios old_termios = tty->init_termios;
+    struct tty_ldisc *ld = RT_NULL;
+    struct termios *new_termios = (struct termios *)arg;
+    int level = 0;
+    int retval = tty_check_change(tty);
+
+    if (retval)
+    {
+        return retval;
+    }
+
+    level = rt_hw_interrupt_disable();
+    tty->init_termios = *new_termios;
+    rt_hw_interrupt_enable(level);
+    ld = tty->ldisc;
+    if (ld != NULL)
+    {
+        if (ld->ops->set_termios)
+        {
+            ld->ops->set_termios(tty, &old_termios);
+        }
+    }
+    return 0;
+}
+
+int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *args)
+{
+    int ret = 0;
+    void *p = (void *)args;
+    struct tty_struct *real_tty = RT_NULL;
+
+    if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
+    {
+        real_tty = tty->other_struct;
+    }
+    else
+    {
+        real_tty = tty;
+    }
+
+    switch(cmd)
+    {
+    case TCGETS:
+    {
+        struct termios *tio = (struct termios *)p;
+        if (tio == RT_NULL)
+        {
+            return -RT_EINVAL;
+        } 
+        
+        rt_memcpy(tio, &real_tty->init_termios, sizeof(real_tty->init_termios));
+        return ret;
+    }
+    case TCSETSF:
+    {
+        return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+    }
+    case TCSETSW:
+    {
+        return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+    }
+    case TCSETS:
+    {
+        return set_termios(real_tty, p, TERMIOS_OLD);
+    }
+    default:
+        break;
+    }
+    return -ENOIOCTLCMD;
+}

+ 181 - 0
components/drivers/tty/tty_ldisc.c

@@ -0,0 +1,181 @@
+#include <tty.h>
+#include <tty_ldisc.h>
+
+#define DBG_TAG               "TTY_LDISC"
+#ifdef RT_TTY_DEBUG
+#define DBG_LVL               DBG_LOG
+#else
+#define DBG_LVL               DBG_INFO
+#endif /* RT_TTY_DEBUG */
+#include <rtdbg.h>
+
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+
+static struct tty_ldisc_ops *get_ldops(int disc)
+{
+    struct tty_ldisc_ops *ldops = RT_NULL;
+    int level = 0;
+    level = rt_hw_interrupt_disable();
+    ldops = tty_ldiscs[disc];
+    if (ldops)
+    {
+        ldops->refcount++;
+    }
+    rt_hw_interrupt_enable(level);
+    return ldops;
+}
+
+static void put_ldops(struct tty_ldisc_ops *ldops)
+{
+    int level = 0;
+
+    level = rt_hw_interrupt_disable();
+    ldops->refcount--;
+    rt_hw_interrupt_enable(level);
+}
+static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
+{
+    struct tty_ldisc *ld = RT_NULL;
+    struct tty_ldisc_ops *ldops = RT_NULL;
+
+    if (disc < N_TTY || disc >= NR_LDISCS)
+    {
+        return RT_NULL;
+    }
+
+    ldops = get_ldops(disc);
+    if (ldops == RT_NULL)
+    {
+        LOG_E("tty ldisc get error\n");
+        return RT_NULL;
+    }
+
+    ld = rt_malloc(sizeof(struct tty_ldisc));
+    if (ld == RT_NULL)
+    {
+        ldops->refcount--;
+        return RT_NULL;
+    }
+
+    ld->ops = ldops;
+    ld->tty = tty;
+
+    return ld;
+}
+
+/**
+ *  tty_ldisc_put       -   release the ldisc
+ *
+ *  Complement of tty_ldisc_get().
+ */
+static void tty_ldisc_put(struct tty_ldisc *ld)
+{
+    if (ld == RT_NULL)
+    {
+        return;
+    }
+
+    put_ldops(ld->ops);
+    rt_free(ld);
+}
+
+/**
+ *  tty_ldisc_close     -   close a line discipline
+ *  @tty: tty we are opening the ldisc on
+ *  @ld: discipline to close
+ *
+ *  A helper close method. Also a convenient debugging and check
+ *  point.
+ */
+
+static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+    if (ld->ops->close)
+    {
+        ld->ops->close(tty);
+    }
+}
+
+/**
+ *  tty_ldisc_kill  -   teardown ldisc
+ *  @tty: tty being released
+ *
+ *  Perform final close of the ldisc and reset tty->ldisc
+ */
+void tty_ldisc_kill(struct tty_struct *tty)
+{
+    if (!tty->ldisc)
+    {
+        return;        
+    }
+
+    /*
+     * Now kill off the ldisc
+     */
+    tty_ldisc_close(tty, tty->ldisc);
+    tty_ldisc_put(tty->ldisc);
+    /* Force an oops if we mess this up */
+    tty->ldisc = NULL;
+}
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+{
+    int ret = 0;
+    int level = 0;
+
+    if (disc < N_TTY || disc >= NR_LDISCS)
+    {
+        return -EINVAL;
+    }
+
+    level = rt_hw_interrupt_disable();
+    tty_ldiscs[disc] = new_ldisc;
+    new_ldisc->num = disc;
+    new_ldisc->refcount = 0;
+    rt_hw_interrupt_enable(level);
+
+    return ret;
+}
+
+/**
+ *  tty_ldisc_release       -   release line discipline
+ *  @tty: tty being shut down (or one end of pty pair)
+ *
+ *  Called during the final close of a tty or a pty pair in order to shut
+ *  down the line discpline layer. On exit, each tty's ldisc is NULL.
+ */
+
+void tty_ldisc_release(struct tty_struct *tty)
+{
+    int level = 0;
+    struct tty_struct *o_tty = tty->other_struct;
+
+    /*
+     * Shutdown this line discipline. As this is the final close,
+     * it does not race with the set_ldisc code path.
+     */
+
+    level = rt_hw_interrupt_disable();
+    tty_ldisc_kill(tty);
+    if (o_tty)
+    {
+        tty_ldisc_kill(o_tty);
+    }
+    rt_hw_interrupt_enable(level);
+
+}
+
+/**
+ *  tty_ldisc_init      -   ldisc setup for new tty
+ *  @tty: tty being allocated
+ *
+ *  Set up the line discipline objects for a newly allocated tty. Note that
+ *  the tty structure is not completely set up when this call is made.
+ */
+
+void tty_ldisc_init(struct tty_struct *tty)
+{
+    struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
+    RT_ASSERT(ld != RT_NULL);
+    tty->ldisc = ld;
+}

+ 2 - 1
components/finsh/shell.c

@@ -593,7 +593,8 @@ void finsh_thread_entry(void *parameter)
             }
             else
             {
-                rt_kprintf("\b \b");
+                if (shell->echo_mode)
+                    rt_kprintf("\b \b");
                 shell->line[shell->line_position] = 0;
             }
 

+ 0 - 4
components/libc/Kconfig

@@ -47,10 +47,6 @@ if RT_USING_LIBC && RT_USING_DFS
         bool "Enable mmap() API"
         default n
 
-    config RT_USING_POSIX_TERMIOS
-        bool "Enable termios APIs"
-        default n
-
     config RT_USING_POSIX_GETLINE
         bool "Enable getline()/getdelim() APIs"
         default n

+ 0 - 13
components/libc/termios/SConscript

@@ -1,13 +0,0 @@
-# RT-Thread building script for component
-
-from building import *
-
-cwd = GetCurrentDir()
-src = Glob('*.c') + Glob('*.cpp')
-CPPPATH = [cwd]
-
-group = DefineGroup('libc', src, 
-    depend = ['RT_USING_LIBC', 'RT_USING_POSIX', 'RT_USING_POSIX_TERMIOS'], 
-    CPPPATH = CPPPATH)
-
-Return('group')

+ 42 - 7
components/lwp/lwp.c

@@ -16,13 +16,14 @@
 
 #include <dfs_posix.h>
 #include <lwp_elf.h>
-#include <lwp_console.h>
 
 #ifndef RT_USING_DFS
 #error "lwp need file system(RT_USING_DFS)"
 #endif
 
 #include "lwp.h"
+#include "lwp_arch.h"
+#include "console.h"
 
 #define DBG_TAG "LWP"
 #define DBG_LVL DBG_WARNING
@@ -42,9 +43,9 @@ static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
 #ifdef DFS_USING_WORKDIR
 extern char working_directory[];
 #endif
+struct termios stdin_termios, old_stdin_termios;
 
 extern void lwp_user_entry(void *args, const void *text, void *ustack, void *k_stack);
-extern int libc_stdio_get_console(void);
 int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]);
 
 void lwp_setcwd(char *buf)
@@ -1188,11 +1189,50 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
             self_lwp = lwp_self();
             if (self_lwp)
             {
+                //lwp->tgroup_leader = &thread; //add thread group leader for lwp
+                lwp->__pgrp = tid;
+                lwp->session = self_lwp->session;
                 /* lwp add to children link */
                 lwp->sibling = self_lwp->first_child;
                 self_lwp->first_child = lwp;
                 lwp->parent = self_lwp;
             }
+            else
+            {
+                //lwp->tgroup_leader = &thread; //add thread group leader for lwp
+                lwp->__pgrp = tid;
+            }
+            if (!bg)
+            {
+                if (lwp->session == -1)
+                {
+                    struct tty_struct *tty = RT_NULL;
+                    tty = (struct tty_struct *)console_tty_get();
+                    lwp->tty = tty;
+                    lwp->tty->pgrp = lwp->__pgrp;
+                    lwp->tty->session = lwp->session;
+                    lwp->tty->foreground = lwp;
+                    tcgetattr(1, &stdin_termios);
+                    old_stdin_termios = stdin_termios;
+                    stdin_termios.c_lflag |= ICANON | ECHO | ECHOCTL;
+                    tcsetattr(1, 0, &stdin_termios);
+                }
+                else
+                {
+                    if (self_lwp != RT_NULL)
+                    {
+                        lwp->tty = self_lwp->tty;
+                        lwp->tty->pgrp = lwp->__pgrp;
+                        lwp->tty->session = lwp->session;
+                        lwp->tty->foreground = lwp;
+                    }
+                    else
+                    {
+                        lwp->tty = RT_NULL;
+                    }
+
+                }
+            }
             thread->lwp = lwp;
 #ifndef ARCH_MM_MMU
             struct lwp_app_head *app_head = (struct lwp_app_head*)lwp->text_entry;
@@ -1214,11 +1254,6 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
                 lwp->debug = debug;
             }
 #endif
-
-            if ((rt_console_get_foreground() == self_lwp) && !bg)
-            {
-                rt_console_set_foreground(lwp);
-            }
             rt_hw_interrupt_enable(level);
 
             rt_thread_startup(thread);

+ 11 - 1
components/lwp/lwp.h

@@ -41,7 +41,9 @@
 
 #ifdef RT_USING_MUSL
 #include <locale.h>
-typedef int32_t pid_t;
+#endif
+#ifdef  RT_USING_TTY
+struct tty_struct;
 #endif
 
 #ifdef __cplusplus
@@ -86,7 +88,12 @@ struct rt_lwp
     void *args;
     uint32_t args_length;
     pid_t pid;
+    pid_t __pgrp; /*Accessed via process_group()*/
+    pid_t tty_old_pgrp;
+    pid_t session;
     rt_list_t t_grp;
+
+    int leader; /*boolean value for session group_leader*/
     struct dfs_fdtable fdt;
     char cmd[RT_NAME_MAX];
 
@@ -102,6 +109,7 @@ struct rt_lwp
     struct rt_user_context user_ctx;
 
     struct rt_wqueue wait_queue; /*for console */
+    struct tty_struct *tty; /* NULL if no tty */
 
     struct lwp_avl_struct *address_search_head; /* for addressed object fast rearch */
     char working_directory[DFS_PATH_MAX];
@@ -137,6 +145,8 @@ void lwp_tid_set_thread(int tid, rt_thread_t thread);
 
 size_t lwp_user_strlen(const char *s, int *err);
 
+/*create by lwp_setsid.c*/
+int setsid(void);
 #ifdef RT_USING_USERSPACE
 void lwp_mmu_switch(struct rt_thread *thread);
 #endif

+ 0 - 546
components/lwp/lwp_console.c

@@ -1,546 +0,0 @@
-/*
- * Copyright (c) 2006-2020, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date           Author       Notes
- * 2020-02-23     Jesven      first version
- */
-
-#include <rthw.h>
-#include <rtdevice.h>
-
-#include "lwp_console.h"
-
-#define DBG_TAG    "CONSOLE"
-#define DBG_LVL    DBG_INFO
-#include <rtdbg.h>
-
-#define CHAR_CTRL_D 0x4
-#define CHAR_CTRL_C 0x3
-
-enum
-{
-    CONSOLE_INIT_FLAG_NONE = 0,
-    CONSOLE_INIT_FLAG_REGED,
-    CONSOLE_INIT_FLAG_INITED,
-};
-
-static struct rt_console_device _console;
-
-rt_inline struct rt_wqueue *wait_queue_get(struct rt_lwp * lwp)
-{
-    if (lwp == RT_PROCESS_KERNEL)
-    {
-        return &_console.wait_queue;
-    }
-    return &lwp->wait_queue;
-}
-
-rt_inline struct rt_wqueue *wait_queue_current_get(void)
-{
-    return wait_queue_get(_console.foreground);
-}
-
-static void console_wakeup_check(struct rt_console_device *console)
-{
-    rt_size_t len = 0;
-    struct rt_wqueue *wq = NULL;
-
-    len = rt_ringbuffer_data_len(&console->input_rb);
-    if (len)
-    {
-        wq = wait_queue_current_get();
-        rt_wqueue_wakeup(wq, (void*)POLLIN);
-    }
-}
-
-static void console_rx_notify(struct rt_device *dev)
-{
-    struct rt_console_device *console = NULL;
-    rt_size_t len = 0;
-    rt_uint8_t ch = 0;
-
-    console = (struct rt_console_device *)dev;
-    RT_ASSERT(console != RT_NULL);
-
-    while (1)
-    {
-        len = rt_device_read(console->iodev, -1, &ch, 1);
-        if (len == 0)
-        {
-            break;
-        }
-        if (ch == CHAR_CTRL_D) /* ctrl-d */
-        {
-            console->foreground = RT_PROCESS_KERNEL;
-        }
-        else if (ch == CHAR_CTRL_C) /* ctrl-c */
-        {
-            struct rt_lwp *lwp = console->foreground;
-
-            if (lwp)
-            {
-                lwp_kill(lwp_to_pid(lwp), SIGINT);
-            }
-        }
-        else
-        {
-            rt_ringbuffer_put_force(&console->input_rb, &ch, 1);
-        }
-    }
-    console_wakeup_check(console);
-}
-
-void rt_console_set_foreground(struct rt_lwp *lwp)
-{
-    rt_base_t level = 0;
-
-    level = rt_hw_interrupt_disable();
-    if (_console.init_flag != CONSOLE_INIT_FLAG_INITED)
-    {
-        goto exit;
-    }
-    _console.foreground = lwp;
-    console_wakeup_check(&_console);
-
-exit:
-    rt_hw_interrupt_enable(level);
-}
-
-struct rt_lwp * rt_console_get_foreground(void)
-{
-    struct rt_lwp *lwp = RT_NULL;
-    rt_base_t level = 0;
-
-    level = rt_hw_interrupt_disable();
-    lwp = _console.foreground;
-    rt_hw_interrupt_enable(level);
-
-    return lwp;
-}
-
-static void iodev_close(struct rt_console_device *console)
-{
-    struct rt_device_notify rx_notify;
-
-    rx_notify.notify = RT_NULL;
-    rx_notify.dev = RT_NULL;
-
-    /* clear notify */
-    rt_device_control(console->iodev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
-    rt_device_close(console->iodev);
-}
-
-static rt_err_t iodev_open(struct rt_console_device *console)
-{
-    rt_err_t ret = RT_EOK;
-    struct rt_device_notify rx_notify;
-    rt_uint16_t oflags = 0;
-
-    rt_device_control(console->iodev, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
-
-    ret = rt_device_open(console->iodev, oflags);
-    if (ret != RT_EOK)
-    {
-        return RT_ERROR;
-    }
-
-    rx_notify.notify = console_rx_notify;
-    rx_notify.dev = (struct rt_device *)console;
-    rt_device_control(console->iodev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
-    return RT_EOK;
-}
-
-struct rt_device *rt_console_get_iodev(void)
-{
-    rt_base_t level = 0;
-    struct rt_device *iodev = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-    iodev = _console.iodev;
-    rt_hw_interrupt_enable(level);
-    return iodev;
-}
-
-struct rt_device *rt_console_set_iodev(struct rt_device *iodev)
-{
-    rt_base_t level = 0;
-    struct rt_device *io_before = RT_NULL;
-    struct rt_console_device *console = RT_NULL;
-
-    RT_ASSERT(iodev != RT_NULL);
-
-    console = &_console;
-
-    level = rt_hw_interrupt_disable();
-
-    RT_ASSERT(console->init_flag >= CONSOLE_INIT_FLAG_REGED);
-
-    io_before = console->iodev;
-
-    if (iodev == io_before)
-    {
-        goto exit;
-    }
-
-    if (console->init_flag >= CONSOLE_INIT_FLAG_INITED)
-    {
-        /* close old device */
-        iodev_close(console);
-    }
-
-    console->iodev = iodev;
-
-    if (console->init_flag >= CONSOLE_INIT_FLAG_INITED)
-    {
-        rt_err_t ret;
-        /* open new device */
-        ret = iodev_open(console);
-        RT_ASSERT(ret == RT_EOK);
-    }
-
-exit:
-    rt_hw_interrupt_enable(level);
-    return io_before;
-}
-
-#ifdef RT_USING_POSIX
-
-/* fops for console */
-static int console_fops_open(struct dfs_fd *fd)
-{
-    int ret = 0;
-    struct rt_device *device = RT_NULL;
-
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-
-    if (fd->fnode->ref_count == 1)
-    {
-        ret = rt_device_open(device, fd->flags);
-    }
-    return ret;
-}
-
-static int console_fops_close(struct dfs_fd *fd)
-{
-    int ret = 0;
-    struct rt_device *device = RT_NULL;
-
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-
-    if (fd->fnode->ref_count == 1)
-    {
-        ret = rt_device_close(device);
-    }
-    return ret;
-}
-
-static int console_fops_read(struct dfs_fd *fd, void *buf, size_t count)
-{
-    rt_base_t level = 0;
-    int size = 0;
-    struct rt_console_device *console = RT_NULL;
-    struct rt_lwp *lwp = RT_NULL;
-    struct rt_wqueue *wq = RT_NULL;
-    int wait_ret = 0;
-
-    console = (struct rt_console_device *)fd->fnode->data;
-    RT_ASSERT(console != RT_NULL);
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-
-    lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
-
-    wq = wait_queue_get(lwp);
-
-    level = rt_hw_interrupt_disable();
-    while (count)
-    {
-        size = rt_device_read((struct rt_device *)console, -1, buf, count);
-        if (size > 0)
-        {
-            break;
-        }
-        if (fd->flags & O_NONBLOCK)
-        {
-            break;
-        }
-        wait_ret = rt_wqueue_wait_interruptible(wq, 0, RT_WAITING_FOREVER);
-        if (wait_ret != 0)
-        {
-            break;
-        }
-    }
-    rt_hw_interrupt_enable(level);
-    if (size < 0)
-    {
-        size = 0;
-    }
-    return size;
-}
-
-static int console_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
-{
-    int size = 0;
-    struct rt_device *device = RT_NULL;
-
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-    size = rt_device_write(device, -1, buf, count);
-    return size;
-}
-
-static int console_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
-{
-    int size = 0;
-    struct rt_device *device = RT_NULL;
-
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-    size = rt_device_control(device, cmd, args);
-    return size;	
-}
-static int console_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req)
-{
-    rt_base_t level = 0;
-    int mask = POLLOUT;
-    struct rt_device *device = RT_NULL;
-    struct rt_console_device *console = RT_NULL;
-    struct rt_wqueue *wq = RT_NULL;
-    struct rt_lwp *lwp = RT_NULL;
-
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-
-    console = (struct rt_console_device *)device;
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-
-    lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
-    wq = wait_queue_get(lwp);
-    rt_poll_add(wq, req);
-
-    level = rt_hw_interrupt_disable();
-    if (lwp == console->foreground)
-    {
-        rt_size_t len;
-
-        len = rt_ringbuffer_data_len(&console->input_rb);
-        if (len)
-        {
-            mask |= POLLIN;
-        }
-    }
-    rt_hw_interrupt_enable(level);
-
-    return mask;
-}
-
-const static struct dfs_file_ops _console_fops =
-{
-    console_fops_open,
-    console_fops_close,
-    console_fops_ioctl,
-    console_fops_read,
-    console_fops_write,
-    RT_NULL, /* flush */
-    RT_NULL, /* lseek */
-    RT_NULL, /* getdents */
-    console_fops_poll,
-};
-
-#endif
-
-/* RT-Thread Device Interface */
-/*
- * This function initializes console device.
- */
-static rt_err_t rt_console_init(struct rt_device *dev)
-{
-    rt_base_t level = 0;
-    rt_err_t result = RT_EOK;
-    struct rt_console_device *console = RT_NULL;
-
-    RT_ASSERT(dev != RT_NULL);
-
-    console = (struct rt_console_device *)dev;
-
-    level = rt_hw_interrupt_disable();
-
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_REGED);
-
-    result = iodev_open(console);
-    if (result != RT_EOK)
-    {
-        goto exit;
-    }
-
-    console->init_flag = CONSOLE_INIT_FLAG_INITED;
-exit:
-    rt_hw_interrupt_enable(level);
-    return result;
-}
-
-static rt_err_t rt_console_open(struct rt_device *dev, rt_uint16_t oflag)
-{
-    rt_err_t result = RT_EOK;
-    struct rt_console_device *console = RT_NULL;
-
-    RT_ASSERT(dev != RT_NULL);
-    console = (struct rt_console_device *)dev;
-    RT_ASSERT(console != RT_NULL);
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-    return result;
-}
-
-static rt_err_t rt_console_close(struct rt_device *dev)
-{
-    rt_err_t result = RT_EOK;
-    struct rt_console_device *console = RT_NULL;
-
-    console = (struct rt_console_device *)dev;
-    RT_ASSERT(console != RT_NULL);
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-    return result;
-}
-
-static rt_size_t rt_console_read(struct rt_device *dev,
-        rt_off_t          pos,
-        void             *buffer,
-        rt_size_t         size)
-{
-    rt_base_t level = 0;
-    rt_size_t len = 0;
-    struct rt_lwp *lwp = RT_NULL;
-    struct rt_console_device *console = RT_NULL;
-
-    console = (struct rt_console_device *)dev;
-    RT_ASSERT(console != RT_NULL);
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-
-    level = rt_hw_interrupt_disable();
-    if (size)
-    {
-        lwp = lwp_self();
-        if (lwp == console->foreground)
-        {
-            len = rt_ringbuffer_data_len(&console->input_rb);
-            if (len > size)
-            {
-                len = size;
-            }
-            if (len)
-            {
-                len = rt_ringbuffer_get(&console->input_rb, buffer, len);
-            }
-        }
-    }
-    rt_hw_interrupt_enable(level);
-
-    return len;
-}
-
-static rt_size_t rt_console_write(struct rt_device *dev,
-        rt_off_t          pos,
-        const void       *buffer,
-        rt_size_t         size)
-{
-    rt_base_t level = 0;
-    rt_size_t len = 0;
-    struct rt_console_device *console = RT_NULL;
-
-    console = (struct rt_console_device *)dev;
-    RT_ASSERT(console != RT_NULL);
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-
-    level = rt_hw_interrupt_disable();
-    len = rt_device_write((struct rt_device *)console->iodev, -1, buffer, size);
-    rt_hw_interrupt_enable(level);
-
-    return len;
-}
-		
-static rt_err_t  rt_console_control(rt_device_t dev, int cmd, void *args)
-{
-	rt_base_t level = 0;
-    rt_size_t len = 0;
-    struct rt_console_device *console = RT_NULL;
-
-    console = (struct rt_console_device *)dev;
-    RT_ASSERT(console != RT_NULL);
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED);
-
-    level = rt_hw_interrupt_disable();
-    len = rt_device_control((struct rt_device *)console->iodev, cmd, args);
-    rt_hw_interrupt_enable(level);
-
-    return len;
-}
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops console_ops =
-{
-    rt_console_init,
-    rt_console_open,
-    rt_console_close,
-    rt_console_read,
-    rt_console_write,
-    rt_console_control,
-};
-#endif
-
-/*
- * console register
- */
-rt_err_t rt_console_register(const char *name, struct rt_device *iodev)
-{
-    rt_base_t level = 0;
-    rt_err_t ret = RT_EOK;
-    struct rt_device *device = RT_NULL;
-    struct rt_console_device *console = &_console;
-
-    level = rt_hw_interrupt_disable();
-    RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_NONE);
-    RT_ASSERT(iodev != RT_NULL);
-
-    device = &(console->parent);
-
-    device->type        = RT_Device_Class_Char;
-
-#ifdef RT_USING_DEVICE_OPS
-    device->ops         = &console_ops;
-#else
-    device->init        = rt_console_init;
-    device->open        = rt_console_open;
-    device->close       = rt_console_close;
-    device->read        = rt_console_read;
-    device->write       = rt_console_write;
-    device->control     = rt_console_control;
-#endif
-
-    /* register a character device */
-    ret = rt_device_register(device, name, 0);
-    if (ret != RT_EOK)
-    {
-        goto exit;
-    }
-
-#ifdef RT_USING_POSIX
-    /* set fops */
-    device->fops = &_console_fops;
-#endif
-
-    console->iodev = iodev;
-    console->foreground = RT_PROCESS_KERNEL;
-    rt_wqueue_init(&(console->wait_queue));
-
-    RT_ASSERT(LWP_CONSOLE_INPUT_BUFFER_SIZE > 0);
-    rt_ringbuffer_init(&console->input_rb, console->input_buf, LWP_CONSOLE_INPUT_BUFFER_SIZE);
-
-    console->init_flag = CONSOLE_INIT_FLAG_REGED;
-exit:
-    rt_hw_interrupt_enable(level);
-    return ret;
-}

+ 0 - 49
components/lwp/lwp_console.h

@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2006-2020, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date           Author       Notes
- * 2020-02-23     Jesven         first version.
- */
-#ifndef  LWP_CONSOLE_H__
-#define  LWP_CONSOLE_H__
-
-#include <lwp.h>
-#include <rtthread.h>
-#include <rtdevice.h>
-
-#include <dfs_posix.h>
-#include <dfs_poll.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define RT_PROCESS_KERNEL RT_NULL
-
-struct rt_console_device
-{
-    struct rt_device parent;
-    int    init_flag;
-    struct rt_device *iodev;
-    struct rt_lwp *foreground;
-    struct rt_wqueue wait_queue; /* for kernel when current == 0 */
-    struct rt_ringbuffer input_rb;
-    rt_uint8_t input_buf[LWP_CONSOLE_INPUT_BUFFER_SIZE];
-};
-
-rt_err_t rt_console_register(const char *name, struct rt_device *iodev);
-
-struct rt_device *rt_console_set_iodev(struct rt_device *iodev);
-struct rt_device *rt_console_get_iodev(void);
-
-void rt_console_set_foreground(struct rt_lwp *lwp);
-struct rt_lwp* rt_console_get_foreground(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  /* LWP_CONSOLE_H__*/

+ 17 - 8
components/lwp/lwp_pid.c

@@ -15,7 +15,7 @@
 
 #include "lwp.h"
 #include "lwp_pid.h"
-#include "lwp_console.h"
+#include "tty.h"
 
 #ifdef RT_USING_USERSPACE
 #include "lwp_user_mm.h"
@@ -130,8 +130,6 @@ static void lwp_pid_set_lwp(pid_t pid, struct rt_lwp *lwp)
     rt_hw_interrupt_enable(level);
 }
 
-int libc_stdio_get_console(void);
-
 static void __exit_files(struct rt_lwp *lwp)
 {
     int fd = lwp->fdt.maxfd - 1;
@@ -332,6 +330,10 @@ struct rt_lwp* lwp_new(void)
     rt_memset(lwp, 0, sizeof(*lwp));
     rt_list_init(&lwp->wait_list);
     lwp->pid = pid;
+    lwp->leader = 0;
+    lwp->session = -1;
+    lwp->tty = RT_NULL;
+    //lwp->tgroup_leader = RT_NULL;
     lwp_pid_set_lwp(pid, lwp);
     rt_list_init(&lwp->t_grp);
     lwp_user_object_lock_init(lwp);
@@ -434,12 +436,19 @@ void lwp_free(struct rt_lwp* lwp)
 
     /* for parent */
     {
-        struct rt_lwp *console_lwp;
-
-        console_lwp = rt_console_get_foreground();
-        if (lwp == console_lwp)
+        extern struct termios old_stdin_termios;
+        struct rt_lwp *self_lwp = (struct rt_lwp *)lwp_self();
+        if (lwp->session == -1)
+        {
+            tcsetattr(1, 0, &old_stdin_termios);
+        }
+        if (lwp->tty != RT_NULL)
         {
-            rt_console_set_foreground(lwp->parent);
+            if (lwp->tty->foreground == lwp)
+            {
+                lwp->tty->foreground = self_lwp;
+                lwp->tty = RT_NULL;
+            }
         }
 
         if (lwp->parent)

+ 27 - 0
components/lwp/lwp_setsid.c

@@ -0,0 +1,27 @@
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "lwp.h"
+//#include "lwp_tid.h"
+#include "lwp_pid.h"
+
+int setsid(void)
+{
+    int err = -EPERM;
+    struct rt_thread *current_thread = rt_thread_self();
+    struct rt_lwp *current_lwp = (struct rt_lwp *)rt_thread_self()->lwp;
+
+    if (current_lwp->session == current_thread->tid)
+    {
+        return err;
+    }
+
+    current_lwp->session = current_thread->tid;
+    current_lwp->__pgrp = current_thread->tid;
+    current_lwp->leader = 1;
+    current_lwp->tty = RT_NULL;
+    current_lwp->tty_old_pgrp = 0;
+
+    err = current_lwp->session;
+    return err;
+}

+ 18 - 3
components/lwp/lwp_syscall.c

@@ -54,7 +54,7 @@
 #include <sal.h>
 #endif /* RT_USING_SAL */
 
-#include <lwp_console.h>
+#include <tty.h>
 #include "lwp_ipc_internal.h"
 
 #define SET_ERRNO(no) rt_set_errno(-(no))
@@ -1550,6 +1550,11 @@ static void lwp_struct_copy(struct rt_lwp *dst, struct rt_lwp *src)
     dst->data_entry = src->data_entry;
     dst->data_size = src->data_size;
     dst->args = src->args;
+    dst->leader = 0;
+    dst->session = src->session;
+    dst->tty_old_pgrp = 0;
+    dst->__pgrp = src->__pgrp;
+    dst->tty = src->tty;
     rt_memcpy(dst->cmd, src->cmd, RT_NAME_MAX);
 
     dst->sa_flags = src->sa_flags;
@@ -1716,9 +1721,9 @@ int _sys_fork(void)
             user_stack, &thread->sp);
     /* new thread never reach there */
     level = rt_hw_interrupt_disable();
-    if (rt_console_get_foreground() == self_lwp)
+    if (lwp->tty != RT_NULL)
     {
-        rt_console_set_foreground(lwp);
+        lwp->tty->foreground = lwp;
     }
     rt_hw_interrupt_enable(level);
     rt_thread_startup(thread);
@@ -3897,6 +3902,15 @@ int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
     return -ENOSYS;
 }
 
+int sys_setsid(void)
+{
+    int ret = 0;
+    ret = setsid();
+    return (ret < 0 ? GET_ERRNO() : ret);
+}
+
+int sys_cacheflush(void *addr, int len, int cache);
+
 const static void* func_table[] =
 {
     (void *)sys_exit,            /* 01 */
@@ -4080,6 +4094,7 @@ const static void* func_table[] =
     (void *)sys_prlimit64,      /* 140 */
     (void *)sys_getrlimit,
     (void *)sys_setrlimit,
+    (void *)sys_setsid,
 };
 
 const void *lwp_get_sys_api(rt_uint32_t number)

+ 0 - 463
components/lwp/unix98pty/lwp_ptmx.c

@@ -1,463 +0,0 @@
-/*
-* Copyright (c) 2006-2018, RT-Thread Development Team
-*
-* SPDX-License-Identifier: Apache-2.0
-*/
-#include "lwp_pty.h"
-
-static struct rt_ptmx_device ptmx, *_ptmx = &ptmx;
-
-rt_inline struct rt_wqueue *ptmx_get_wq(struct rt_lwp *lwp)
-{
-    if (lwp == RT_NULL)
-    {
-        return &_ptmx->wq;
-    }
-    return &lwp->wait_queue;
-}
-
-/* 查找空闲 pts 设备 */
-static struct rt_pts_device *find_freepts(void)
-{
-    for(int i = 0; i < LWP_PTY_PTS_SIZE; i++)
-    {
-        if (_ptmx->pts[i].flags == PTY_INIT_FLAG_NONE)
-        {
-            _ptmx->pts[i].flags = PTY_INIT_FLAG_ALLOCED;
-            return &_ptmx->pts[i];
-        }
-    }
-    return RT_NULL;
-}
-
-/* 通过 fd(ptmx) 获取 pts 设备句柄 */
-static struct rt_pts_device *ptmxfd2pts(struct dfs_fd *fd)
-{
-    int ptmx_fd;
-
-    ptmx_fd = fd_get_fd_index(fd);
-    for(int i = 0; i < LWP_PTY_PTS_SIZE; i++)
-    {
-        if (_ptmx->pts[i].flags != PTY_INIT_FLAG_NONE)
-        {
-            if (_ptmx->pts[i].ptmx_fd == ptmx_fd)
-            {
-                return &_ptmx->pts[i];
-            }
-        }
-    }
-    return RT_NULL;
-}
-
-static rt_size_t ptmx_read(struct rt_pts_device *pts, rt_off_t pos, void *buffer, rt_size_t size)
-{
-    rt_base_t level = 0;
-    rt_size_t len = 0;
-
-    level = rt_hw_interrupt_disable();
-    if (size)
-    {
-        len = rt_ringbuffer_data_len(&pts->srb);
-        if (len > size)
-        {
-            len = size;
-        }
-        if (len)
-        {
-            len = rt_ringbuffer_get(&pts->srb, buffer, len);
-        }
-    }
-    rt_hw_interrupt_enable(level);
-
-    return len;
-}
-
-static rt_size_t ptmx_write(struct rt_pts_device *pts, rt_off_t pos, const void *buffer, rt_size_t count)
-{
-    rt_base_t level = 0;
-    rt_size_t size = 0;
-
-    if (*(char *)buffer == '\r')
-    {
-        *(char *)buffer = '\n';
-    }
-
-    level = rt_hw_interrupt_disable();
-    size = lwp_pts_push_mrb(pts, (void *)buffer, count);
-    rt_hw_interrupt_enable(level);
-
-    return size;
-}
-
-static int ptmx_file_open(struct dfs_fd *fd)
-{
-    rt_base_t level = 0;
-    int ret = -1;
-    struct rt_ptmx_device *ptmx = LWP_PTY_GET_PTMX(fd);
-    struct rt_pts_device *pts = RT_NULL;
-    int ptmx_fd = -1;
-    struct rt_device *device = RT_NULL;
-    struct rt_lwp *lwp = RT_NULL;
-    struct rt_wqueue *wq = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-
-    pts = find_freepts();
-    if (pts == RT_NULL)
-    {
-        LOG_E("no pts device, maximum number is %d", LWP_PTY_PTS_SIZE);
-        ret = (-ENODEV);
-        goto _exit;
-    }
-
-    /* 注册 pts 设备 */
-    ptmx_fd = fd_get_fd_index(fd);
-    if (ptmx_fd < 0)
-    {
-        pts->flags = PTY_INIT_FLAG_NONE; /* free pts */
-    }
-    ret = lwp_pts_register(pts, ptmx_fd, ptmx->pts_index);
-    if (ret != RT_EOK)
-    {
-        fd_release(ptmx_fd);
-        pts->flags = PTY_INIT_FLAG_NONE; /* free pts */
-        LOG_E("register pts%d fail", ptmx->pts_index);
-        ret = (-EIO);
-        goto _exit;
-    }
-
-    /* 打开设备 */
-    device = (struct rt_device *)fd->fnode->data;
-    if (fd->fnode->ref_count == 1)
-    {
-        ret = rt_device_open(device, fd->flags);
-        RT_ASSERT(ret == 0);
-    }
-
-    lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
-    wq = ptmx_get_wq(lwp);
-    pts->swq = wq; /* 将当前等待队列设置到 pts 中,用于 ptmx 写数据后唤醒 lwp 读数据 */
-    pts->ptmx_fd = ptmx_fd;
-    ptmx->pts_index++;
-
-    ret = 0;
-
-_exit:
-    rt_hw_interrupt_enable(level);
-    return ret;
-}
-
-static int ptmx_file_close(struct dfs_fd *fd)
-{
-    rt_base_t level = 0;
-    int ret = 0;
-    struct rt_device *device = RT_NULL;
-    struct rt_pts_device *pts = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-    if (fd->fnode->ref_count == 1)
-    {
-        pts = ptmxfd2pts(fd);
-        if (pts && pts->mwq)
-        {
-            pts->ptmx_fd = RT_NULL;
-            rt_wqueue_wakeup(pts->mwq, (void*)POLLIN);
-        }
-        device = (struct rt_device *)fd->fnode->data;
-        ret = rt_device_close(device);
-    }
-    rt_hw_interrupt_enable(level);
-
-    return ret;
-}
-
-static int ptmx_file_read(struct dfs_fd *fd, void *buf, size_t count)
-{
-    rt_base_t level = 0;
-    size_t size = 0;
-    struct rt_pts_device *pts = RT_NULL;
-    int wait_ret = 0;
-
-    level = rt_hw_interrupt_disable();
-
-    pts = ptmxfd2pts(fd);
-    if (pts)
-    {
-        while (count)
-        {
-            size = ptmx_read(pts, -1, buf, count);
-            if (size > 0)
-            {
-                break;
-            }
-
-            if (fd->flags & O_NONBLOCK)
-            {
-                break;
-            }
-
-            /* 当直接读的时候,没有数据就挂起,等待 ptmx 写入数据后唤醒 */
-            wait_ret = rt_wqueue_wait_interruptible(pts->swq, 0, RT_WAITING_FOREVER);
-            if (wait_ret != 0)
-            {
-                break;
-            }
-        }
-
-    }
-    rt_hw_interrupt_enable(level);
-
-    if (size < 0)
-    {
-        size = 0;
-    }
-
-    return size;
-}
-
-static int ptmx_file_write(struct dfs_fd *fd, const void *buf, size_t count)
-{
-    int size = 0;
-    struct rt_pts_device *pts = RT_NULL;
-    rt_base_t level = 0;
-
-    level = rt_hw_interrupt_disable();
-
-    pts = ptmxfd2pts(fd);
-    if (pts)
-    {
-        size = ptmx_write(pts, -1, buf, count);
-    }
-
-    rt_hw_interrupt_enable(level);
-
-    return size;
-}
-
-static int ptmx_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
-{
-    rt_base_t level = 0;
-
-    level = rt_hw_interrupt_disable();
-
-    switch (cmd) {
-    case TIOCSPTLCK:    /* Set PT Lock (disallow slave open) */
-    {
-        struct rt_pts_device *pts = ptmxfd2pts(fd);
-        if (pts)
-        {
-            pts->pts_lock = *(int *)args;
-            rt_hw_interrupt_enable(level);
-            return 0;
-        }
-        else
-        {
-            rt_hw_interrupt_enable(level);
-            return (-EIO);
-        }
-    }
-    case TIOCGPTLCK:    /* Get PT Lock status */
-    {
-        struct rt_pts_device *pts = ptmxfd2pts(fd);
-        if (pts)
-        {
-            *(int *)args = pts->pts_lock;
-            rt_hw_interrupt_enable(level);
-            return 0;
-        }
-        else
-        {
-            rt_hw_interrupt_enable(level);
-            return (-EIO);
-        }
-    }
-    case TIOCPKT:       /* Set PT packet mode */
-        // return pty_set_pktmode(tty, (int __user *)arg);
-        rt_hw_interrupt_enable(level);
-        return 0;
-    case TIOCGPKT:      /* Get PT packet mode */
-        // return pty_get_pktmode(tty, (int __user *)arg);
-        rt_hw_interrupt_enable(level);
-        return 0;
-    case TIOCGPTN:      /* Get PT Number */
-    {
-        struct rt_pts_device *pts = ptmxfd2pts(fd);
-        if (pts)
-        {
-            /* 获取 ptmx 对应的 pts 的编号 */
-            *(int *)args = pts->pts_index;
-            rt_hw_interrupt_enable(level);
-            return 0;
-        }
-        else
-        {
-            rt_hw_interrupt_enable(level);
-            return (-EIO);
-        }
-    }
-    case TIOCSIG:       /* Send signal to other side of pty */
-        // return pty_signal(tty, (int) arg);
-        rt_hw_interrupt_enable(level);
-        return 0;
-
-#if defined(RT_USING_POSIX_TERMIOS)
-    case TCSETS:
-    {
-        // pts = ptmxfd2pts(fd);
-        // rt_memcpy(&pts->tio, args, sizeof(struct termios));
-        rt_hw_interrupt_enable(level);
-        return (-EINVAL);
-    }
-    case TCGETS:
-    {
-        // pts = ptmxfd2pts(fd);
-        // rt_memcpy(args, &pts->tio, sizeof(struct termios));
-        rt_hw_interrupt_enable(level);
-        return (-EINVAL);
-    }
-#endif /* RT_USING_POSIX_TERMIOS */
-    }
-
-    rt_hw_interrupt_enable(level);
-    return (-EINVAL);
-}
-
-static int ptmx_file_poll(struct dfs_fd *fd, struct rt_pollreq *req)
-{
-    rt_base_t level = 0;
-    int mask = POLLOUT;
-    rt_size_t len;
-    struct rt_pts_device *pts = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-
-    pts = ptmxfd2pts(fd);
-    if (!pts)
-    {
-        mask |= POLLIN;
-        goto _exit;
-    }
-
-    rt_poll_add(pts->swq, req);
-
-    /* 判断是否有数据可以 read 设备 */
-    len = rt_ringbuffer_data_len(&pts->srb);
-    if (len)
-    {
-        mask |= POLLIN;
-    }
-
-_exit:
-    rt_hw_interrupt_enable(level);
-
-    return mask;
-}
-
-static rt_err_t ptmx_device_init(struct rt_device *dev)
-{
-    return RT_EOK;
-}
-
-static rt_err_t ptmx_device_open(struct rt_device *dev, rt_uint16_t oflag)
-{
-    return RT_EOK;
-}
-
-static rt_err_t ptmx_device_close(struct rt_device *dev)
-{
-    return RT_EOK;
-}
-
-static rt_size_t ptmx_device_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
-{
-    return size;
-}
-
-static rt_size_t ptmx_device_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
-{
-    return size;
-}
-
-static rt_err_t ptmx_device_control(rt_device_t dev, int cmd, void *args)
-{
-    return RT_EOK;
-}
-
-#ifdef RT_USING_POSIX
-const static struct dfs_file_ops ptmx_file_ops =
-{
-    ptmx_file_open,
-    ptmx_file_close,
-    ptmx_file_ioctl,
-    ptmx_file_read,
-    ptmx_file_write,
-    RT_NULL, /* flush */
-    RT_NULL, /* lseek */
-    RT_NULL, /* getdents */
-    ptmx_file_poll,
-};
-#endif /* RT_USING_POSIX */
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops ptmx_device_ops =
-{
-    ptmx_device_init,
-    ptmx_device_open,
-    ptmx_device_close,
-    ptmx_device_read,
-    ptmx_device_write,
-    ptmx_device_control,
-};
-#endif /* RT_USING_DEVICE_OPS */
-
-static int lwp_ptmx_register(void)
-{
-    rt_err_t ret = RT_EOK;
-    rt_base_t level = 0;
-    struct rt_device *device = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-
-    if (_ptmx->flags != PTY_INIT_FLAG_NONE)
-    {
-        ret = (-RT_EBUSY);
-        goto _exit;
-    }
-
-    device = &_ptmx->parent;
-    device->type    = RT_Device_Class_Char;
-#ifdef RT_USING_DEVICE_OPS
-    device->ops     = &ptmx_device_ops;
-#else
-    device->init    = ptmx_device_init;
-    device->open    = ptmx_device_open;
-    device->close   = ptmx_device_close;
-    device->read    = ptmx_device_read;
-    device->write   = ptmx_device_write;
-    device->control = ptmx_device_control;
-#endif /* RT_USING_DEVICE_OPS */
-
-    ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
-    if (ret != RT_EOK)
-    {
-        ret = -RT_EIO;
-        goto _exit;
-    }
-
-#ifdef RT_USING_POSIX
-    /* set fops */
-    device->fops = &ptmx_file_ops;
-#endif
-
-    rt_wqueue_init(&_ptmx->wq);
-    rt_mutex_init(&_ptmx->mutex, "ptmx", RT_IPC_FLAG_FIFO);
-    rt_memset(_ptmx->pts, 0x00, sizeof(struct rt_pts_device)*LWP_PTY_PTS_SIZE);
-    _ptmx->pts_index = 0;
-    _ptmx->flags = PTY_INIT_FLAG_REGED;
-
-_exit:
-    rt_hw_interrupt_enable(level);
-
-    return ret;
-}
-INIT_DEVICE_EXPORT(lwp_ptmx_register);

+ 0 - 557
components/lwp/unix98pty/lwp_pts.c

@@ -1,557 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include "lwp_pty.h"
-
-rt_inline struct rt_wqueue *pts_get_wq(struct rt_pts_device *pts, struct rt_lwp *lwp)
-{
-    if (lwp == RT_NULL)
-    {
-        return &pts->wq;
-    }
-    return &lwp->wait_queue;
-}
-
-static int pts_file_open(struct dfs_fd *fd)
-{
-    int ret = 0;
-    struct rt_device *device = RT_NULL;
-    rt_base_t level = 0;
-    struct rt_lwp *lwp = RT_NULL;
-    struct rt_wqueue *wq = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-
-    if (fd->fnode->ref_count == 1)
-    {
-        struct rt_pts_device *pts = LWP_PTY_GET_PTS(fd);
-
-        lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
-        wq = pts_get_wq(pts, lwp);
-        pts->mwq = wq;
-
-        ret = rt_device_open(device, fd->flags);
-    }
-    rt_hw_interrupt_enable(level);
-    return ret;
-}
-
-static int pts_file_close(struct dfs_fd *fd)
-{
-    int ret = 0;
-    struct rt_device *device = RT_NULL;
-    struct rt_pts_device *pts = LWP_PTY_GET_PTS(fd);
-    rt_base_t level = 0;
-
-    level = rt_hw_interrupt_disable();
-
-    device = (struct rt_device *)fd->fnode->data;
-    RT_ASSERT(device != RT_NULL);
-
-    if (fd->fnode->ref_count == 1)
-    {
-        ret = rt_device_close(device);
-        lwp_pts_unregister(pts);
-    }
-
-    rt_hw_interrupt_enable(level);
-
-    return ret;
-}
-
-static int pts_file_read(struct dfs_fd *fd, void *buf, size_t count)
-{
-    rt_base_t level = 0;
-    size_t size = 0;
-    struct rt_pts_device *pts = LWP_PTY_GET_PTS(fd);
-    int wait_ret = 0;
-
-    level = rt_hw_interrupt_disable();
-
-    while (count)
-    {
-        size = rt_device_read(&pts->parent, -1, buf, count);
-        if (size > 0)
-        {
-            break;
-        }
-
-        if (fd->flags & O_NONBLOCK)
-        {
-            break;
-        }
-
-        if (!pts->ptmx_fd) /* ptmux closed */
-        {
-            break;
-        }
-
-        /* 当直接读的时候,没有数据就挂起,等待 ptmx 写入数据后唤醒 */
-        wait_ret = rt_wqueue_wait_interruptible(pts->mwq, 0, RT_WAITING_FOREVER);
-        if (wait_ret != 0)
-        {
-            break;
-        }
-    }
-
-    rt_hw_interrupt_enable(level);
-
-    if (size < 0)
-    {
-        size = 0;
-    }
-
-    return size;
-}
-
-static int pts_file_write(struct dfs_fd *fd, const void *buf, size_t count)
-{
-    int size = 0;
-    rt_base_t level = 0;
-
-    level = rt_hw_interrupt_disable();
-
-    struct rt_pts_device *pts = LWP_PTY_GET_PTS(fd);
-    RT_ASSERT(pts != RT_NULL);
-    size = rt_device_write((struct rt_device *)pts, -1, buf, count);
-
-    rt_hw_interrupt_enable(level);
-
-    return size;
-}
-
-static int pts_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
-{
-    rt_base_t level = 0;
-    struct rt_pts_device *pts = LWP_PTY_GET_PTS(fd);
-
-    level = rt_hw_interrupt_disable();
-
-    switch (cmd) {
-    case TIOCSWINSZ:
-        rt_memcpy(&pts->winsize, args, sizeof(struct winsize));
-        LOG_D("set /dev/pts/%d winsize: %d %d %d %d",
-            pts->pts_index,
-            pts->winsize.ws_row, pts->winsize.ws_col,
-            pts->winsize.ws_xpixel, pts->winsize.ws_ypixel);
-        rt_hw_interrupt_enable(level);
-        return 0;
-    case TIOCGWINSZ:
-        rt_memcpy(args, &pts->winsize, sizeof(struct winsize));
-        rt_hw_interrupt_enable(level);
-        return 0;
-
-    case TIOCSCTTY:
-        LOG_D("TODO PTS TIOCSCTTY CMD");
-        rt_hw_interrupt_enable(level);
-        return 0;
-
-#if defined(RT_USING_POSIX_TERMIOS)
-    case TCSETS:
-        rt_memcpy(&pts->tio, args, sizeof(struct termios));
-        rt_hw_interrupt_enable(level);
-        return 0;
-    case TCGETS:
-        rt_memcpy(args, &pts->tio, sizeof(struct termios));
-        rt_hw_interrupt_enable(level);
-        return 0;
-#endif /* RT_USING_POSIX_TERMIOS */
-    }
-
-    rt_hw_interrupt_enable(level);
-    return -EINVAL;
-}
-
-static int pts_file_poll(struct dfs_fd *fd, struct rt_pollreq *req)
-{
-    rt_base_t level = 0;
-    int mask = POLLOUT;
-    rt_size_t len;
-    struct rt_pts_device *pts = LWP_PTY_GET_PTS(fd);
-
-    level = rt_hw_interrupt_disable();
-
-    rt_poll_add(pts->mwq, req);
-
-    /* 判断是否有数据可以 read 设备 */
-    len = rt_ringbuffer_data_len(&pts->mrb);
-    if (len)
-    {
-        mask |= POLLIN;
-    }
-
-    rt_hw_interrupt_enable(level);
-
-    return mask;
-}
-
-static rt_err_t pts_device_init(struct rt_device *dev)
-{
-    return RT_EOK;
-}
-
-static rt_err_t pts_device_open(struct rt_device *dev, rt_uint16_t oflag)
-{
-    // TODO: oflag = O_NOCTTY
-    return RT_EOK;
-}
-
-static rt_err_t pts_device_close(struct rt_device *dev)
-{
-    return RT_EOK;
-}
-
-static rt_size_t pts_device_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
-{
-    rt_base_t level = 0;
-    rt_size_t len = 0;
-    struct rt_pts_device *pts = (struct rt_pts_device *)dev;
-
-    level = rt_hw_interrupt_disable();
-    if (size)
-    {
-        len = rt_ringbuffer_data_len(&pts->mrb);
-        if (len > size)
-        {
-            len = size;
-        }
-        if (len)
-        {
-            len = rt_ringbuffer_get(&pts->mrb, buffer, len);
-        }
-    }
-    rt_hw_interrupt_enable(level);
-
-    return len;
-}
-
-static rt_size_t pts_device_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t count)
-{
-    rt_base_t level = 0;
-    rt_size_t size = 0;
-    struct rt_pts_device *pts = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-    pts = (struct rt_pts_device *)dev;
-    size = lwp_pts_push_srb(pts, (void *)buffer, count);
-    rt_hw_interrupt_enable(level);
-
-    return size;
-}
-
-static rt_err_t pts_device_control(rt_device_t dev, int cmd, void *args)
-{
-    return RT_EOK;
-}
-
-#ifdef RT_USING_POSIX
-const static struct dfs_file_ops pts_file_ops =
-{
-    pts_file_open,
-    pts_file_close,
-    pts_file_ioctl,
-    pts_file_read,
-    pts_file_write,
-    RT_NULL, /* flush */
-    RT_NULL, /* lseek */
-    RT_NULL, /* getdents */
-    pts_file_poll,
-};
-#endif /* RT_USING_POSIX */
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops pts_device_ops =
-{
-    pts_device_init,
-    pts_device_open,
-    pts_device_close,
-    pts_device_read,
-    pts_device_write,
-    pts_device_control,
-};
-#endif /* RT_USING_DEVICE_OPS */
-
-int lwp_pts_isbusy(struct rt_pts_device *pts)
-{
-    RT_ASSERT(pts != RT_NULL);
-    return (pts->parent.ref_count > 0) ? 1 : 0;
-}
-
-static rt_size_t dispose_char(struct rt_pts_device *pts, char ch)
-{
-    rt_uint8_t is_lfcr = 0;
-
-    if (ch < 0)
-    {
-        return 0;
-    }
-
-    /* 判断输入是否超过了缓存, 截断超出部分 */
-    if (pts->line_position >= LWP_PTY_INPUT_BFSZ && ch != '\r' && ch != '\n')
-    {
-        return 0;
-    }
-
-    /* handle control key:
-     * up key  : 0x1b 0x5b 0x41
-     * down key: 0x1b 0x5b 0x42
-     * right key:0x1b 0x5b 0x43
-     * left key: 0x1b 0x5b 0x44
-     */
-    if (ch == 0x1b)
-    {
-        pts->stat = LWP_PTS_INPUT_WAIT_SPEC_KEY;
-        return 0;
-    }
-    else if (pts->stat == LWP_PTS_INPUT_WAIT_SPEC_KEY)
-    {
-        if (ch == 0x5b)
-        {
-            pts->stat = LWP_PTS_INPUT_WAIT_FUNC_KEY;
-            return 0;
-        }
-
-        pts->stat = LWP_PTS_INPUT_WAIT_NORMAL;
-    }
-    else if (pts->stat == LWP_PTS_INPUT_WAIT_FUNC_KEY)
-    {
-        pts->stat = LWP_PTS_INPUT_WAIT_NORMAL;
-
-        if (ch == 0x41) /* up key */
-        {
-            LOG_D("find input UP key");
-            char buff[] = "^[[A";
-            rt_ringbuffer_put_force(&pts->srb, (void *)buff, rt_strlen(buff)); /* 回显 */
-            return 0;
-        }
-        else if (ch == 0x42) /* down key */
-        {
-            LOG_D("find input DOWN key");
-            char buff[] = "^[[B";
-            rt_ringbuffer_put_force(&pts->srb, (void *)buff, rt_strlen(buff)); /* 回显 */
-            return 0;
-        }
-        else if (ch == 0x44) /* left key */
-        {
-            LOG_D("find input RIGHT key");
-            char buff[] = "^[[C";
-            rt_ringbuffer_put_force(&pts->srb, (void *)buff, rt_strlen(buff)); /* 回显 */
-            return 0;
-        }
-        else if (ch == 0x43) /* right key */
-        {
-            LOG_D("find input LEFT key");
-            char buff[] = "^[[D";
-            rt_ringbuffer_put_force(&pts->srb, (void *)buff, rt_strlen(buff)); /* 回显 */
-            return 0;
-        }
-    }
-
-    /* received null or error */
-    if (ch == '\0' || ch == 0xFF) return 0;
-    else if (ch == '\t')
-    {
-        /* 补全不回显, 但是由会传递给 sh 处理 */
-        pts->line[pts->line_position] = ch;
-        pts->line_position++;
-        return 0;
-    }
-    else if (ch == 0x7f || ch == 0x08) /* handle backspace key */
-    {
-        LOG_D("find input backspace key");
-
-        char buff[] = "\b \b";
-        rt_ringbuffer_put_force(&pts->srb, (void *)buff, rt_strlen(buff)); /* 回显 */
-        pts->line_position--;
-        return 0;
-    }
-
-    /* handle end of line, break */
-    else if (ch == '\r' || ch == '\n')
-    {
-        is_lfcr = 1;
-    }
-
-    rt_ringbuffer_put_force(&pts->srb, (void *)&ch, 1); /* 回显 */
-
-    /* 将没有回车的一行输入缓存到 line 中, 当发现回车换行后再统一输出到 ptmx 处理 */
-    // LOG_D("%d", ch);
-    pts->line[pts->line_position] = ch;
-    pts->line_position++;
-
-    return is_lfcr;
-}
-
-rt_size_t lwp_pts_push_mrb(struct rt_pts_device *pts, void *buffer, rt_size_t size)
-{
-    rt_size_t len = 0;
-    rt_uint8_t is_lfcr = 0;
-    RT_ASSERT(pts != RT_NULL);
-
-    if (pts->echo)
-    {
-        /* 按照字符处理 */
-        for(int index = 0; index < size; index++)
-        {
-            char *ptr = (char *)buffer;
-            is_lfcr = dispose_char(pts, *(ptr + index));
-        }
-
-        /* 判断是否发现回车换行了 */
-        if (is_lfcr)
-        {
-            // LOG_D("pts->line_position = %d", pts->line_position);
-            rt_ringbuffer_put_force(&pts->mrb, (void *)pts->line, pts->line_position);
-            pts->line_position = 0;
-            rt_memset(pts->line, 0x00, LWP_PTY_INPUT_BFSZ+1);
-        }
-    }
-    else /* 不处理直接传递给 sh 处理回显和字符 */
-    {
-        rt_ringbuffer_put_force(&pts->mrb, buffer, size);
-    }
-
-    len = rt_ringbuffer_data_len(&pts->mrb);
-    if (len && pts->mwq)
-    {
-        // 先读阻塞,用于唤醒阻塞的 lwp 进程
-        rt_wqueue_wakeup(pts->mwq, (void*)POLLIN);
-    }
-
-    return len;
-}
-
-rt_size_t lwp_pts_push_srb(struct rt_pts_device *pts, void *buffer, rt_size_t size)
-{
-    rt_size_t len = 0;
-    RT_ASSERT(pts != RT_NULL);
-    rt_ringbuffer_put_force(&pts->srb, buffer, size);
-    len = rt_ringbuffer_data_len(&pts->srb);
-
-    if (len && pts->swq)
-    {
-        // 先读阻塞,用于唤醒阻塞的 lwp 进程
-        rt_wqueue_wakeup(pts->swq, (void*)POLLIN);
-    }
-    return len;
-}
-
-int lwp_pts_unregister(struct rt_pts_device *pts)
-{
-    rt_err_t ret = RT_EOK;
-    rt_base_t level = 0;
-    struct rt_wqueue *wq = RT_NULL;
-
-    level = rt_hw_interrupt_disable();
-    if (pts->parent.ref_count > 0)
-    {
-        ret = (-RT_EBUSY);
-        goto _exit;
-    }
-
-    wq = pts->swq;
-    rt_mutex_detach(&pts->mutex);
-    rt_memset(&pts->winsize, 0x00, sizeof(struct winsize));
-    pts->pts_lock = 0;
-    pts->ptmx_fd = 0;
-    pts->pts_index = 0;
-    pts->flags = PTY_INIT_FLAG_NONE;
-    if (wq)
-    {
-        rt_wqueue_wakeup(wq, (void*)POLLIN);
-    }
-    rt_hw_interrupt_enable(level);
-    ret = rt_device_unregister(&pts->parent);
-
-_exit:
-    rt_hw_interrupt_enable(level);
-
-    return ret;
-}
-
-int lwp_pts_register(struct rt_pts_device *pts, int ptmx_fd, int pts_index)
-{
-    rt_err_t ret = RT_EOK;
-    rt_base_t level = 0;
-    struct rt_device *device = RT_NULL;
-    char name[20];
-
-    level = rt_hw_interrupt_disable();
-
-    if (pts->flags != PTY_INIT_FLAG_ALLOCED)
-    {
-        LOG_E("pts%d has been registered", pts_index);
-        ret = (-RT_EBUSY);
-        goto _exit;
-    }
-
-    device = &pts->parent;
-    device->type    = RT_Device_Class_Char;
-#ifdef RT_USING_DEVICE_OPS
-    device->ops     = &pts_device_ops;
-#else
-    device->init    = pts_device_init;
-    device->open    = pts_device_open;
-    device->close   = pts_device_close;
-    device->read    = pts_device_read;
-    device->write   = pts_device_write;
-    device->control = pts_device_control;
-#endif /* RT_USING_DEVICE_OPS */
-
-    rt_snprintf(name, sizeof(name), "pts%d", pts_index);
-    ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
-    if (ret != RT_EOK)
-    {
-        LOG_E("pts%d register failed", pts_index);
-        ret = -RT_EIO;
-        goto _exit;
-    }
-
-#ifdef RT_USING_POSIX
-    /* set fops */
-    device->fops = &pts_file_ops;
-#endif
-
-    rt_wqueue_init(&pts->wq);
-    rt_ringbuffer_init(&pts->mrb, pts->mbuf, LWP_PTY_INPUT_BFSZ);
-    rt_ringbuffer_init(&pts->srb, pts->sbuf, LWP_PTY_INPUT_BFSZ);
-
-    pts->echo = 1;
-    pts->stat = LWP_PTS_INPUT_WAIT_NORMAL;
-    pts->line_position = 0;
-    rt_memset(pts->line, 0x00, sizeof(pts->line));
-
-    rt_mutex_init(&pts->mutex, name, RT_IPC_FLAG_FIFO);
-    pts->mwq = RT_NULL;
-    rt_memset(&pts->winsize, 0x00, sizeof(struct winsize));
-    pts->pts_lock = 1;
-    pts->ptmx_fd = ptmx_fd;
-    pts->pts_index = pts_index;
-    pts->flags = PTY_INIT_FLAG_REGED;
-
-_exit:
-    rt_hw_interrupt_enable(level);
-
-    return ret;
-}
-
-#include <rtthread.h>
-#include <rtdevice.h>
-int pts_dump(int argc, char *argv[])
-{
-    struct rt_pts_device *pts = RT_NULL;
-    int mrblen = 0, srblen = 0;
-    rt_device_t dev = rt_device_find(argv[1]);
-
-    pts = (struct rt_pts_device *)dev;
-    mrblen = rt_ringbuffer_data_len(&pts->mrb);
-    srblen = rt_ringbuffer_data_len(&pts->srb);
-
-    LOG_I("dev %s mrblen = %d srblen = %d", argv[1], mrblen, srblen);
-    return 0;
-}
-MSH_CMD_EXPORT(pts_dump, dump /dev/pts/%d device ringbuffer info.);

+ 0 - 119
components/lwp/unix98pty/lwp_pty.h

@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#ifndef __LWP_PTY_H__
-#define __LWP_PTY_H__
-
-#include <rtthread.h>
-#include <rtdevice.h>
-#include <lwp.h>
-#include <lwp_user_mm.h>
-
-#if defined(RT_USING_POSIX_TERMIOS)
-#include <posix_termios.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DBG_ENABLE
-#if defined(LWP_PTY_USING_DEBUG)
-#define DBG_LEVEL DBG_LOG
-#else
-#define DBG_LEVEL DBG_INFO
-#endif
-#define DBG_COLOR
-#include <rtdbg.h>
-
-#ifndef LWP_PTY_INPUT_BFSZ
-#define LWP_PTY_INPUT_BFSZ 1024
-#endif /* LWP_PTY_INPUT_BFSZ */
-
-#ifndef LWP_PTY_PTS_SIZE
-#define LWP_PTY_PTS_SIZE 3
-#endif /* LWP_PTY_PTS_SIZE */
-
-#ifndef LWP_PTY_HISTORY_LINE_SIZE
-#define LWP_PTY_HISTORY_LINE_SIZE 5
-#endif /* LWP_PTY_HISTORY_LINE_SIZE */
-
-#define LWP_PTY_GET_PTMX(fd) ((struct rt_ptmx_device *)(fd->fnode->data))
-#define LWP_PTY_GET_PTS(fd)  ((struct rt_pts_device *)(fd->fnode->data))
-
-enum lwp_pty_init_flag
-{
-    PTY_INIT_FLAG_NONE = 0,
-    PTY_INIT_FLAG_ALLOCED,
-    PTY_INIT_FLAG_REGED,
-};
-typedef enum lwp_pty_init_flag lwp_pty_init_flag_t;
-
-enum lwp_pts_input_stat
-{
-    LWP_PTS_INPUT_WAIT_NORMAL = 0,
-    LWP_PTS_INPUT_WAIT_SPEC_KEY,
-    LWP_PTS_INPUT_WAIT_FUNC_KEY,
-};
-typedef enum lwp_pts_input_stat lwp_pts_input_stat_t;
-
-struct rt_pts_device
-{
-    struct rt_device parent;
-    int flags;
-    int pts_lock;
-    int pts_index; /* index = /dev/pts/%d */
-    struct rt_mutex mutex;
-
-    // ptmx
-    struct rt_ptmx_device *ptmx;
-    int ptmx_fd;
-
-    // win attribute
-    struct winsize winsize;
-
-#if defined(RT_USING_POSIX_TERMIOS)
-    struct termios tio;
-#endif /* RT_USING_POSIX_TERMIOS */
-
-    /* console echo */
-    lwp_pts_input_stat_t stat;
-    rt_uint8_t echo;
-    char line[LWP_PTY_INPUT_BFSZ+1];
-    rt_uint16_t line_position;
-
-    struct rt_wqueue *mwq;
-    struct rt_wqueue *swq;
-    struct rt_wqueue wq;      /* for kernel */
-    struct rt_ringbuffer mrb; /* ptmx w(master) ==> pts r(slave) */
-    struct rt_ringbuffer srb; /* pts w(slave) ==> ptmx r(master) */
-    rt_uint8_t mbuf[LWP_PTY_INPUT_BFSZ];
-    rt_uint8_t sbuf[LWP_PTY_INPUT_BFSZ];
-};
-
-struct rt_ptmx_device
-{
-    struct rt_device parent;
-    int flags;
-    struct rt_mutex mutex;
-    struct rt_wqueue wq;
-
-    int pts_index;
-    struct rt_pts_device pts[LWP_PTY_PTS_SIZE];
-};
-
-/* pty */
-extern int lwp_pts_isbusy(struct rt_pts_device *pts);
-extern rt_size_t lwp_pts_push_mrb(struct rt_pts_device *pts, void *buffer, rt_size_t size);
-extern rt_size_t lwp_pts_push_srb(struct rt_pts_device *pts, void *buffer, rt_size_t size);
-extern int lwp_pts_unregister(struct rt_pts_device *pts);
-extern int lwp_pts_register(struct rt_pts_device *pts, int ptmx_fd, int pts_index);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWP_PTY_H__ */

+ 1 - 0
include/libc/libc_errno.h

@@ -16,6 +16,7 @@
 #if defined(RT_USING_NEWLIB) || defined(RT_USING_MUSL) || defined(_WIN32) || defined(__ARMCC_GNUC__)
 /* use errno.h file in toolchains */
 #include <errno.h>
+#define ENOIOCTLCMD	    (ERROR_BASE_NO + 515) /* No ioctl command */
 #endif
 
 #if defined(__CC_ARM)

+ 236 - 98
src/kservice.c

@@ -29,7 +29,7 @@
 #ifdef RT_USING_LWP
 #include <lwp.h>
 #include <lwp_user_mm.h>
-#include <lwp_console.h>
+#include <console.h>
 #endif
 
 /* use precision */
@@ -55,7 +55,7 @@ static rt_device_t _console_device = RT_NULL;
  */
 rt_err_t rt_get_errno(void)
 {
-    rt_thread_t tid;
+    rt_thread_t tid = RT_NULL;
 
     if (rt_interrupt_get_nest() != 0)
     {
@@ -65,7 +65,9 @@ rt_err_t rt_get_errno(void)
 
     tid = rt_thread_self();
     if (tid == RT_NULL)
-        return __rt_errno;
+    {
+        return __rt_errno;        
+    }
 
     return tid->error;
 }
@@ -78,7 +80,7 @@ RTM_EXPORT(rt_get_errno);
  */
 void rt_set_errno(rt_err_t error)
 {
-    rt_thread_t tid;
+    rt_thread_t tid = RT_NULL;
 
     if (rt_interrupt_get_nest() != 0)
     {
@@ -107,14 +109,18 @@ RTM_EXPORT(rt_set_errno);
  */
 int *_rt_errno(void)
 {
-    rt_thread_t tid;
+    rt_thread_t tid = RT_NULL;
 
     if (rt_interrupt_get_nest() != 0)
-        return (int *)&__rt_errno;
+    {
+        return (int *)&__rt_errno;        
+    }
 
     tid = rt_thread_self();
     if (tid != RT_NULL)
-        return (int *) & (tid->error);
+    {
+        return (int *) & (tid->error);        
+    }
 
     return (int *)&__rt_errno;
 }
@@ -143,10 +149,10 @@ void *rt_memset(void *s, int c, rt_ubase_t count)
 #define UNALIGNED(X)    ((long)X & (LBLOCKSIZE - 1))
 #define TOO_SMALL(LEN)  ((LEN) < LBLOCKSIZE)
 
-    unsigned int i;
+    unsigned int i = 0;
     char *m = (char *)s;
-    unsigned long buffer;
-    unsigned long *aligned_addr;
+    unsigned long buffer = 0;
+    unsigned long *aligned_addr = RT_NULL;
     unsigned int d = c & 0xff;  /* To avoid sign extension, copy C to an
                                 unsigned variable.  */
 
@@ -167,7 +173,9 @@ void *rt_memset(void *s, int c, rt_ubase_t count)
         {
             buffer = 0;
             for (i = 0; i < LBLOCKSIZE; i ++)
-                buffer = (buffer << 8) | d;
+            {
+                buffer = (buffer << 8) | d;                
+            }
         }
 
         while (count >= LBLOCKSIZE * 4)
@@ -217,17 +225,21 @@ void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
 {
 #ifdef RT_USING_TINY_SIZE
     char *tmp = (char *)dst, *s = (char *)src;
-    rt_ubase_t len;
+    rt_ubase_t len = 0;
 
     if (tmp <= s || tmp > (s + count))
     {
         while (count--)
-            *tmp ++ = *s ++;
+        {
+            *tmp ++ = *s ++;            
+        }
     }
     else
     {
         for (len = count; len > 0; len --)
-            tmp[len - 1] = s[len - 1];
+        {
+            tmp[len - 1] = s[len - 1];            
+        }
     }
 
     return dst;
@@ -241,8 +253,8 @@ void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
 
     char *dst_ptr = (char *)dst;
     char *src_ptr = (char *)src;
-    long *aligned_dst;
-    long *aligned_src;
+    long *aligned_dst = RT_NULL;
+    long *aligned_src = RT_NULL;
     int len = count;
 
     /* If the size is small, or either SRC or DST is unaligned,
@@ -275,7 +287,9 @@ void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
     }
 
     while (len--)
-        *dst_ptr++ = *src_ptr++;
+    {
+        *dst_ptr++ = *src_ptr++;        
+    }
 
     return dst;
 #undef UNALIGNED
@@ -306,12 +320,16 @@ void *rt_memmove(void *dest, const void *src, rt_ubase_t n)
         s += n;
 
         while (n--)
-            *(--tmp) = *(--s);
+        {
+            *(--tmp) = *(--s);            
+        }
     }
     else
     {
         while (n--)
-            *tmp++ = *s++;
+        {
+            *tmp++ = *s++;            
+        }
     }
 
     return dest;
@@ -329,12 +347,16 @@ RTM_EXPORT(rt_memmove);
  */
 rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count)
 {
-    const unsigned char *su1, *su2;
+    const unsigned char *su1 = RT_NULL, *su2 = RT_NULL;
     int res = 0;
 
     for (su1 = (const unsigned char *)cs, su2 = (const unsigned char *)ct; 0 < count; ++su1, ++su2, count--)
+    {
         if ((res = *su1 - *su2) != 0)
-            break;
+        {
+            break;              
+        }      
+    }
 
     return res;
 }
@@ -350,17 +372,23 @@ RTM_EXPORT(rt_memcmp);
  */
 char *rt_strstr(const char *s1, const char *s2)
 {
-    int l1, l2;
+    int l1 = 0, l2 = 0;
 
     l2 = rt_strlen(s2);
     if (!l2)
-        return (char *)s1;
+    {
+        return (char *)s1;        
+    }
+
     l1 = rt_strlen(s1);
     while (l1 >= l2)
     {
         l1 --;
         if (!rt_memcmp(s1, s2, l2))
-            return (char *)s1;
+        {
+            return (char *)s1;            
+        }
+
         s1 ++;
     }
 
@@ -378,7 +406,7 @@ RTM_EXPORT(rt_strstr);
  */
 rt_int32_t rt_strcasecmp(const char *a, const char *b)
 {
-    int ca, cb;
+    int ca = 0, cb = 0;
 
     do
     {
@@ -417,7 +445,10 @@ char *rt_strncpy(char *dst, const char *src, rt_ubase_t n)
             {
                 /* NUL pad the remaining n-1 bytes */
                 while (--n != 0)
-                    *d++ = 0;
+                {
+                    *d++ = 0;                    
+                }
+
                 break;
             }
         } while (--n != 0);
@@ -443,7 +474,10 @@ rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count)
     while (count)
     {
         if ((__res = *cs - *ct++) != 0 || !*cs++)
-            break;
+        {
+            break;            
+        }
+
         count --;
     }
 
@@ -484,7 +518,7 @@ RTM_EXPORT(rt_strcmp);
  */
 rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen)
 {
-    const char *sc;
+    const char *sc = RT_NULL;
 
     for (sc = s; *sc != '\0' && (rt_ubase_t)(sc - s) < maxlen; ++sc) /* nothing */
         ;
@@ -503,7 +537,7 @@ RTM_EXPORT(rt_strnlen);
  */
 rt_size_t rt_strlen(const char *s)
 {
-    const char *sc;
+    const char *sc = RT_NULL;
 
     for (sc = s; *sc != '\0'; ++sc) /* nothing */
         ;
@@ -526,7 +560,9 @@ char *rt_strdup(const char *s)
     char *tmp = (char *)rt_malloc(len);
 
     if (!tmp)
-        return RT_NULL;
+    {
+        return RT_NULL;        
+    }
 
     rt_memcpy(tmp, s, len);
 
@@ -561,7 +597,7 @@ RTM_EXPORT(rt_show_version);
 #ifdef RT_PRINTF_LONGLONG
 rt_inline int divide(long long *n, int base)
 {
-    int res;
+    int res = 0;
 
     /* optimized for processor which does not support divide instructions. */
     if (base == 10)
@@ -580,7 +616,7 @@ rt_inline int divide(long long *n, int base)
 #else
 rt_inline int divide(long *n, int base)
 {
-    int res;
+    int res = 0;
 
     /* optimized for processor which does not support divide instructions. */
     if (base == 10)
@@ -602,7 +638,9 @@ rt_inline int skip_atoi(const char **s)
 {
     register int i = 0;
     while (_ISDIGIT(**s))
-        i = i * 10 + *((*s)++) - '0';
+    {
+        i = i * 10 + *((*s)++) - '0';        
+    }
 
     return i;
 }
@@ -640,24 +678,26 @@ static char *print_number(char *buf,
                           int   type)
 #endif
 {
-    char c, sign;
+    char c = 0, sign = 0;
 #ifdef RT_PRINTF_LONGLONG
-    char tmp[32];
+    char tmp[32] = {0};
 #else
-    char tmp[16];
+    char tmp[16] = {0};
 #endif
     int precision_bak = precision;
-    const char *digits;
+    const char *digits = RT_NULL;
     static const char small_digits[] = "0123456789abcdef";
     static const char large_digits[] = "0123456789ABCDEF";
-    register int i;
-    register int size;
+    register int i = 0;
+    register int size = 0;
 
     size = s;
 
     digits = (type & LARGE) ? large_digits : small_digits;
     if (type & LEFT)
-        type &= ~ZEROPAD;
+    {
+        type &= ~ZEROPAD;        
+    }
 
     c = (type & ZEROPAD) ? '0' : ' ';
 
@@ -671,33 +711,47 @@ static char *print_number(char *buf,
             num = -num;
         }
         else if (type & PLUS)
-            sign = '+';
+        {
+            sign = '+';            
+        }
         else if (type & SPACE)
-            sign = ' ';
+        {
+            sign = ' ';            
+        }
     }
 
 #ifdef RT_PRINTF_SPECIAL
     if (type & SPECIAL)
     {
         if (base == 16)
-            size -= 2;
+        {
+            size -= 2;            
+        }
         else if (base == 8)
-            size--;
+        {
+            size--;            
+        }
     }
 #endif
 
     i = 0;
     if (num == 0)
-        tmp[i++] = '0';
+    {
+        tmp[i++] = '0';        
+    }
     else
     {
         while (num != 0)
-            tmp[i++] = digits[divide(&num, base)];
+        {
+            tmp[i++] = digits[divide(&num, base)];            
+        }
     }
 
 #ifdef RT_PRINTF_PRECISION
     if (i > precision)
-        precision = i;
+    {
+        precision = i;        
+    }
     size -= precision;
 #else
     size -= i;
@@ -706,12 +760,17 @@ static char *print_number(char *buf,
     if (!(type & (ZEROPAD | LEFT)))
     {
         if ((sign) && (size > 0))
-            size--;
+        {
+            size--;            
+        }
 
         while (size-- > 0)
         {
             if (buf < end)
-                *buf = ' ';
+            {
+                *buf = ' ';               
+            }
+
             ++ buf;
         }
     }
@@ -732,13 +791,19 @@ static char *print_number(char *buf,
         if (base == 8)
         {
             if (buf < end)
-                *buf = '0';
+            {
+                *buf = '0';                
+            }
+
             ++ buf;
         }
         else if (base == 16)
         {
             if (buf < end)
-                *buf = '0';
+            {
+                *buf = '0';                
+            }
+
             ++ buf;
             if (buf < end)
             {
@@ -755,7 +820,10 @@ static char *print_number(char *buf,
         while (size-- > 0)
         {
             if (buf < end)
-                *buf = c;
+            {
+                *buf = c;                
+            }
+
             ++ buf;
         }
     }
@@ -764,7 +832,10 @@ static char *print_number(char *buf,
     while (i < precision--)
     {
         if (buf < end)
-            *buf = '0';
+        {
+            *buf = '0';            
+        }
+
         ++ buf;
     }
 #endif
@@ -773,14 +844,20 @@ static char *print_number(char *buf,
     while (i-- > 0 && (precision_bak != 0))
     {
         if (buf < end)
-            *buf = tmp[i];
+        {
+            *buf = tmp[i];            
+        }
+
         ++ buf;
     }
 
     while (size-- > 0)
     {
         if (buf < end)
-            *buf = ' ';
+        {
+            *buf = ' ';            
+        }
+
         ++ buf;
     }
 
@@ -793,21 +870,21 @@ rt_int32_t rt_vsnprintf(char       *buf,
                         va_list     args)
 {
 #ifdef RT_PRINTF_LONGLONG
-    unsigned long long num;
+    unsigned long long num = 0;
 #else
-    long num;
+    long num = 0;
 #endif
-    int i, len;
-    char *str, *end, c;
-    const char *s;
+    int i = 0, len = 0;
+    char *str = RT_NULL, *end = RT_NULL, c = 0;
+    const char *s = RT_NULL;
 
-    rt_uint8_t base;            /* the base of number */
-    rt_uint8_t flags;           /* flags to print number */
-    rt_uint8_t qualifier;       /* 'h', 'l', or 'L' for integer fields */
-    rt_int32_t field_width;     /* width of output field */
+    rt_uint8_t base = 0;            /* the base of number */
+    rt_uint8_t flags = 0;           /* flags to print number */
+    rt_uint8_t qualifier = 0;       /* 'h', 'l', or 'L' for integer fields */
+    rt_int32_t field_width = 0;     /* width of output field */
 
 #ifdef RT_PRINTF_PRECISION
-    int precision;      /* min. # of digits for integers and max for a string */
+    int precision = 0;      /* min. # of digits for integers and max for a string */
 #endif
 
     str = buf;
@@ -825,7 +902,10 @@ rt_int32_t rt_vsnprintf(char       *buf,
         if (*fmt != '%')
         {
             if (str < end)
-                *str = *fmt;
+            {
+                *str = *fmt;                
+            }
+
             ++ str;
             continue;
         }
@@ -847,7 +927,10 @@ rt_int32_t rt_vsnprintf(char       *buf,
 
         /* get field width */
         field_width = -1;
-        if (_ISDIGIT(*fmt)) field_width = skip_atoi(&fmt);
+        if (_ISDIGIT(*fmt))
+        {
+            field_width = skip_atoi(&fmt);            
+        }
         else if (*fmt == '*')
         {
             ++ fmt;
@@ -866,14 +949,20 @@ rt_int32_t rt_vsnprintf(char       *buf,
         if (*fmt == '.')
         {
             ++ fmt;
-            if (_ISDIGIT(*fmt)) precision = skip_atoi(&fmt);
+            if (_ISDIGIT(*fmt))
+            {
+                precision = skip_atoi(&fmt);                
+            }
             else if (*fmt == '*')
             {
                 ++ fmt;
                 /* it's the next argument */
                 precision = va_arg(args, int);
             }
-            if (precision < 0) precision = 0;
+            if (precision < 0)
+            {
+                precision = 0;
+            }
         }
 #endif
         /* get the conversion qualifier */
@@ -912,7 +1001,10 @@ rt_int32_t rt_vsnprintf(char       *buf,
 
             /* get character */
             c = (rt_uint8_t)va_arg(args, int);
-            if (str < end) *str = c;
+            if (str < end)
+            {
+                *str = c;
+            }
             ++ str;
 
             /* put width */
@@ -925,11 +1017,17 @@ rt_int32_t rt_vsnprintf(char       *buf,
 
         case 's':
             s = va_arg(args, char *);
-            if (!s) s = "(NULL)";
+            if (!s)
+            {
+                s = "(NULL)";
+            }
 
             len = rt_strlen(s);
 #ifdef RT_PRINTF_PRECISION
-            if (precision > 0 && len > precision) len = precision;
+            if (precision > 0 && len > precision)
+            {
+                len = precision;
+            }
 #endif
 
             if (!(flags & LEFT))
@@ -973,7 +1071,10 @@ rt_int32_t rt_vsnprintf(char       *buf,
             continue;
 
         case '%':
-            if (str < end) *str = '%';
+            if (str < end)
+            {
+                *str = '%';
+            }
             ++ str;
             continue;
 
@@ -995,12 +1096,18 @@ rt_int32_t rt_vsnprintf(char       *buf,
             break;
 
         default:
-            if (str < end) *str = '%';
+            if (str < end)
+            {
+                *str = '%';
+            }
             ++ str;
 
             if (*fmt)
             {
-                if (str < end) *str = *fmt;
+                if (str < end)
+                {
+                    *str = *fmt;
+                }
                 ++ str;
             }
             else
@@ -1011,24 +1118,36 @@ rt_int32_t rt_vsnprintf(char       *buf,
         }
 
 #ifdef RT_PRINTF_LONGLONG
-        if (qualifier == 'L') num = va_arg(args, long long);
+        if (qualifier == 'L')
+        {
+            num = va_arg(args, long long);
+        }
         else if (qualifier == 'l')
 #else
         if (qualifier == 'l')
 #endif
         {
             num = va_arg(args, long);
-            if (flags & SIGN) num = (rt_int32_t)num;
+            if (flags & SIGN)
+            {
+                num = (rt_int32_t)num;
+            }
         }
         else if (qualifier == 'h')
         {
             num = (rt_uint16_t)va_arg(args, rt_int32_t);
-            if (flags & SIGN) num = (rt_int16_t)num;
+            if (flags & SIGN)
+            {
+                num = (rt_int16_t)num;
+            }
         }
         else
         {
             num = va_arg(args, long);
-            if (flags & SIGN) num = (rt_int32_t)num;
+            if (flags & SIGN)
+            {
+                num = (rt_int32_t)num;
+            }
         }
 #ifdef RT_PRINTF_PRECISION
         str = print_number(str, end, num, base, field_width, precision, flags);
@@ -1039,7 +1158,10 @@ rt_int32_t rt_vsnprintf(char       *buf,
 
     if (size > 0)
     {
-        if (str < end) *str = '\0';
+        if (str < end)
+        {
+            *str = '\0';
+        }
         else
         {
             end[-1] = '\0';
@@ -1062,7 +1184,7 @@ RTM_EXPORT(rt_vsnprintf);
  */
 rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...)
 {
-    rt_int32_t n;
+    rt_int32_t n = 0;
     va_list args;
 
     va_start(args, fmt);
@@ -1094,7 +1216,7 @@ RTM_EXPORT(rt_vsprintf);
  */
 rt_int32_t rt_sprintf(char *buf, const char *format, ...)
 {
-    rt_int32_t n;
+    rt_int32_t n = 0;
     va_list arg_ptr;
 
     va_start(arg_ptr, format);
@@ -1131,19 +1253,20 @@ RTM_EXPORT(rt_console_get_device);
 rt_device_t rt_console_set_device(const char *name)
 {
 #ifdef RT_USING_LWP
-    rt_device_t new_iodev, old_iodev = RT_NULL;
-
+    rt_device_t new_iodev = RT_NULL, old_iodev = RT_NULL;
+extern void console_init();
+    console_init(); /*add line discipline*/
     /* find new console device */
     new_iodev = rt_device_find(name);
     if (new_iodev != RT_NULL)
     {
         if (_console_device != RT_NULL)
         {
-            old_iodev = rt_console_set_iodev(new_iodev);
+            old_iodev = console_set_iodev(new_iodev);
         }
         else
         {
-            rt_console_register("console", new_iodev);
+            console_register("console", new_iodev);
             _console_device = rt_device_find("console");
             rt_device_open(_console_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM);
         }
@@ -1194,7 +1317,10 @@ RTM_EXPORT(rt_hw_console_output);
  */
 void rt_kputs(const char *str)
 {
-    if (!str) return;
+    if (!str)
+    {
+        return;
+    }
 
 #ifdef RT_USING_DEVICE
     if (_console_device == RT_NULL)
@@ -1222,7 +1348,7 @@ void rt_kputs(const char *str)
 void rt_kprintf(const char *fmt, ...)
 {
     va_list args;
-    rt_size_t length;
+    rt_size_t length = 0;
     static char rt_log_buf[RT_CONSOLEBUF_SIZE];
 
     va_start(args, fmt);
@@ -1233,7 +1359,10 @@ void rt_kprintf(const char *fmt, ...)
      * length. */
     length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
     if (length > RT_CONSOLEBUF_SIZE - 1)
-        length = RT_CONSOLEBUF_SIZE - 1;
+    {
+        length = RT_CONSOLEBUF_SIZE - 1;        
+    }
+
 #ifdef RT_USING_DEVICE
     if (_console_device == RT_NULL)
     {
@@ -1267,10 +1396,10 @@ RTM_EXPORT(rt_kprintf);
  */
 void *rt_malloc_align(rt_size_t size, rt_size_t align)
 {
-    void *ptr;
-    void *align_ptr;
-    int uintptr_size;
-    rt_size_t align_size;
+    void *ptr = RT_NULL;
+    void *align_ptr = RT_NULL;
+    int uintptr_size = 0;
+    rt_size_t align_size = 0;
 
     /* sizeof pointer */
     uintptr_size = sizeof(void*);
@@ -1313,7 +1442,7 @@ RTM_EXPORT(rt_malloc_align);
  */
 void rt_free_align(void *ptr)
 {
-    void *real_ptr;
+    void *real_ptr = RT_NULL;
 
     real_ptr = (void *) * (rt_ubase_t *)((rt_ubase_t)ptr - sizeof(void *));
     rt_free(real_ptr);
@@ -1354,16 +1483,25 @@ const rt_uint8_t __lowest_bit_bitmap[] =
  */
 int __rt_ffs(int value)
 {
-    if (value == 0) return 0;
+    if (value == 0)
+    {
+        return 0;
+    }
 
     if (value & 0xff)
-        return __lowest_bit_bitmap[value & 0xff] + 1;
+    {
+        return __lowest_bit_bitmap[value & 0xff] + 1;        
+    }
 
     if (value & 0xff00)
-        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;
+    {
+        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;        
+    }
 
     if (value & 0xff0000)
-        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;
+    {
+        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;        
+    }
 
     return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
 }