diff --git a/bsp/imx6ull-artpi-smart/drivers/board.c b/bsp/imx6ull-artpi-smart/drivers/board.c index d7590bc35c901de1645214f061ce832866ea2198..246266b4d4dfd06344f7dda952d1cadd04e7e052 100644 --- a/bsp/imx6ull-artpi-smart/drivers/board.c +++ b/bsp/imx6ull-artpi-smart/drivers/board.c @@ -106,6 +106,7 @@ void rt_hw_board_init(void) SystemClockInit(); rt_components_board_init(); + console_init(); rt_console_set_device(RT_CONSOLE_DEVICE_NAME); rt_thread_idle_sethook(idle_wfi); diff --git a/bsp/qemu-vexpress-a9/.config b/bsp/qemu-vexpress-a9/.config index 505e9b1c2224f7e5616e00b9152f0f1c8ce27444..b8cc05afd4cffe7284305b748fb05100ba7c2a46 100644 --- a/bsp/qemu-vexpress-a9/.config +++ b/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 diff --git a/bsp/qemu-vexpress-a9/rtconfig.h b/bsp/qemu-vexpress-a9/rtconfig.h index 896f1e8ebff1b8caeace64ca8255c862476bf6cd..a0e50b4e24bf1c23d484046fcf20d8c69f8a46a7 100644 --- a/bsp/qemu-vexpress-a9/rtconfig.h +++ b/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 */ diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 52e8c7a9090802d5563abe5721072bb979a4d68a..8e6a17eef57d656896db942c46e373f868b0e8a0 100755 --- a/components/drivers/Kconfig +++ b/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 diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index f0050278ed0769998151eccaf385c3c1d3f6a1fc..a58f2264ff2ddd2ff1ab1716474b3e2e92614380 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -38,9 +38,8 @@ #include #include -#ifdef RT_USING_POSIX_TERMIOS #include -#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) diff --git a/components/drivers/tty/SConscript b/components/drivers/tty/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..55595aabc280e7543f9ff752e82f3be86c0fa011 --- /dev/null +++ b/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') diff --git a/components/lwp/lwp_console.c b/components/drivers/tty/console.c similarity index 32% rename from components/lwp/lwp_console.c rename to components/drivers/tty/console.c index 5b91700a8da7fa762bb503ae598cced84bcadedf..58368ec61a4b491d904b0ee58b1077bcefe4736d 100644 --- a/components/lwp/lwp_console.c +++ b/components/drivers/tty/console.c @@ -1,127 +1,65 @@ /* - * Copyright (c) 2006-2020, RT-Thread Development Team + * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes - * 2020-02-23 Jesven first version + * 2021.12.07 linzhenxing first version */ - -#include -#include - -#include "lwp_console.h" - -#define DBG_TAG "CONSOLE" -#define DBG_LVL DBG_INFO +#include +#include +#include +#include + +#define DBG_TAG "CONSOLE" +#ifdef RT_TTY_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_INFO +#endif /* RT_TTY_DEBUG */ #include -#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 struct tty_struct console_driver; 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; + struct tty_struct *console = NULL; + int len = 0; + int lens = 0; + char ch = 0; + char buf[1024] = {0}; - console = (struct rt_console_device *)dev; + console = (struct tty_struct *)dev; RT_ASSERT(console != RT_NULL); while (1) { - len = rt_device_read(console->iodev, -1, &ch, 1); + len = rt_device_read(console->driver, -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 */ + lens += len; + buf[lens-1] = ch; + if (lens > 1024) { - 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); + break; } } - 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) + if (console->ldisc->ops->receive_buf) { - goto exit; + console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens); } - _console.foreground = lwp; - console_wakeup_check(&_console); - -exit: - rt_hw_interrupt_enable(level); } -struct rt_lwp * rt_console_get_foreground(void) +struct tty_struct *console_tty_get(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; + return &console_driver; } -static void iodev_close(struct rt_console_device *console) +static void iodev_close(struct tty_struct *console) { struct rt_device_notify rx_notify; @@ -129,19 +67,19 @@ static void iodev_close(struct rt_console_device *console) rx_notify.dev = RT_NULL; /* clear notify */ - rt_device_control(console->iodev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify); - rt_device_close(console->iodev); + rt_device_control(console->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify); + rt_device_close(console->driver); } -static rt_err_t iodev_open(struct rt_console_device *console) +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->iodev, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags); + rt_device_control(console->driver, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags); - ret = rt_device_open(console->iodev, oflags); + ret = rt_device_open(console->driver, oflags); if (ret != RT_EOK) { return RT_ERROR; @@ -149,51 +87,51 @@ static rt_err_t iodev_open(struct rt_console_device *console) 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); + rt_device_control(console->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify); return RT_EOK; } -struct rt_device *rt_console_get_iodev(void) +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.iodev; + iodev = console_driver.driver; rt_hw_interrupt_enable(level); return iodev; } -struct rt_device *rt_console_set_iodev(struct rt_device *iodev) +struct rt_device *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; + struct tty_struct *console = RT_NULL; RT_ASSERT(iodev != RT_NULL); - console = &_console; + console = &console_driver; level = rt_hw_interrupt_disable(); - RT_ASSERT(console->init_flag >= CONSOLE_INIT_FLAG_REGED); + RT_ASSERT(console->init_flag >= TTY_INIT_FLAG_REGED); - io_before = console->iodev; + io_before = console->driver; if (iodev == io_before) { goto exit; } - if (console->init_flag >= CONSOLE_INIT_FLAG_INITED) + if (console->init_flag >= TTY_INIT_FLAG_INITED) { /* close old device */ iodev_close(console); } - console->iodev = iodev; + console->driver = iodev; - if (console->init_flag >= CONSOLE_INIT_FLAG_INITED) + if (console->init_flag >= TTY_INIT_FLAG_INITED) { rt_err_t ret; /* open new device */ @@ -206,153 +144,6 @@ exit: 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. @@ -361,15 +152,15 @@ 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; + struct tty_struct *console = RT_NULL; RT_ASSERT(dev != RT_NULL); - console = (struct rt_console_device *)dev; + console = (struct tty_struct *)dev; level = rt_hw_interrupt_disable(); - RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_REGED); + RT_ASSERT(console->init_flag == TTY_INIT_FLAG_REGED); result = iodev_open(console); if (result != RT_EOK) @@ -377,7 +168,7 @@ static rt_err_t rt_console_init(struct rt_device *dev) goto exit; } - console->init_flag = CONSOLE_INIT_FLAG_INITED; + console->init_flag = TTY_INIT_FLAG_INITED; exit: rt_hw_interrupt_enable(level); return result; @@ -386,23 +177,23 @@ exit: 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; + struct tty_struct *console = RT_NULL; RT_ASSERT(dev != RT_NULL); - console = (struct rt_console_device *)dev; + console = (struct tty_struct *)dev; RT_ASSERT(console != RT_NULL); - RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED); + 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 rt_console_device *console = RT_NULL; + struct tty_struct *console = RT_NULL; - console = (struct rt_console_device *)dev; + console = (struct tty_struct *)dev; RT_ASSERT(console != RT_NULL); - RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED); + RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED); return result; } @@ -411,34 +202,7 @@ static rt_size_t rt_console_read(struct rt_device *dev, 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; } @@ -449,31 +213,31 @@ static rt_size_t rt_console_write(struct rt_device *dev, { rt_base_t level = 0; rt_size_t len = 0; - struct rt_console_device *console = RT_NULL; + struct tty_struct *console = RT_NULL; - console = (struct rt_console_device *)dev; + console = (struct tty_struct *)dev; RT_ASSERT(console != RT_NULL); - RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED); + RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED); level = rt_hw_interrupt_disable(); - len = rt_device_write((struct rt_device *)console->iodev, -1, buffer, size); + 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_base_t level = 0; rt_size_t len = 0; - struct rt_console_device *console = RT_NULL; + struct tty_struct *console = RT_NULL; - console = (struct rt_console_device *)dev; + console = (struct tty_struct *)dev; RT_ASSERT(console != RT_NULL); - RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_INITED); + RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED); level = rt_hw_interrupt_disable(); - len = rt_device_control((struct rt_device *)console->iodev, cmd, args); + len = rt_device_control((struct rt_device *)console->driver, cmd, args); rt_hw_interrupt_enable(level); return len; @@ -490,19 +254,19 @@ const static struct rt_device_ops console_ops = rt_console_control, }; #endif - /* * console register */ -rt_err_t rt_console_register(const char *name, struct rt_device *iodev) + 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 rt_console_device *console = &_console; + struct tty_struct *console = &console_driver; level = rt_hw_interrupt_disable(); - RT_ASSERT(console->init_flag == CONSOLE_INIT_FLAG_NONE); + RT_ASSERT(console->init_flag == TTY_INIT_FLAG_NONE); RT_ASSERT(iodev != RT_NULL); device = &(console->parent); @@ -520,26 +284,40 @@ rt_err_t rt_console_register(const char *name, struct rt_device *iodev) 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 */ - device->fops = &_console_fops; + console_set_fops(&con_fops); + device->fops = &con_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; + 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; diff --git a/components/drivers/tty/include/console.h b/components/drivers/tty/include/console.h new file mode 100644 index 0000000000000000000000000000000000000000..779d816d4b14fc050bb510a5e708f7a8dc0239ba --- /dev/null +++ b/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 +#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 diff --git a/components/libc/termios/posix_termios.h b/components/drivers/tty/include/posix_termios.h similarity index 67% rename from components/libc/termios/posix_termios.h rename to components/drivers/tty/include/posix_termios.h index c61191b7dcf5d6b0980e6f502f4f7520487d01ff..6f4caa230c31e529f8fc6701c2c7f067972beb37 100644 --- a/components/libc/termios/posix_termios.h +++ b/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 #include @@ -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 *); diff --git a/components/drivers/tty/include/tty.h b/components/drivers/tty/include/tty.h new file mode 100644 index 0000000000000000000000000000000000000000..681c472808cc301d15ceccb73fb193f2cecf4816 --- /dev/null +++ b/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 +#include +#include +#ifdef RT_USING_LWP +#include +#endif +#if defined(RT_USING_POSIX) +#include +#include +#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 */ +#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__*/ diff --git a/components/drivers/tty/include/tty_ldisc.h b/components/drivers/tty/include/tty_ldisc.h new file mode 100644 index 0000000000000000000000000000000000000000..6accb118ea4f254a1bd27cf23ea5ca8a4c853e6c --- /dev/null +++ b/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 +#include +#include +#include +#if defined(RT_USING_POSIX) +#include +#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_ diff --git a/components/drivers/tty/n_tty.c b/components/drivers/tty/n_tty.c new file mode 100644 index 0000000000000000000000000000000000000000..2eff9278917ed8fadcaa24afe7521f07935eb616 --- /dev/null +++ b/components/drivers/tty/n_tty.c @@ -0,0 +1,2045 @@ +/* + * 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 +#include +#include +#if defined(RT_USING_POSIX) +#include +#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 + +/* 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; + + 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; + + /* + * 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, num_bs; + + 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); + + rt_device_t device = (rt_device_t)fd->fnode->data; + if (fd->fnode->ref_count == 1) + { + ret = rt_device_open(device, fd->flags); + } + 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; + 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); +} diff --git a/components/libc/termios/posix_termios.c b/components/drivers/tty/posix_termios.c similarity index 88% rename from components/libc/termios/posix_termios.c rename to components/drivers/tty/posix_termios.c index 7051ac54c2cd1399890a7cc807877720a69cdecb..801ace68a26244321e529ac3768cf979e429c9e6 100644 --- a/components/libc/termios/posix_termios.c +++ b/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 #include #include #include -#include +#include 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); diff --git a/components/drivers/tty/pty.c b/components/drivers/tty/pty.c new file mode 100644 index 0000000000000000000000000000000000000000..050b99e2e9a608f14c3d7e75aa25687333fb89d3 --- /dev/null +++ b/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 +#include +#include + +#define DBG_TAG "PTY" +#ifdef RT_TTY_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_INFO +#endif /* RT_TTY_DEBUG */ +#include + +#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); diff --git a/components/drivers/tty/tty.c b/components/drivers/tty/tty.c new file mode 100644 index 0000000000000000000000000000000000000000..0d68e9c81def1440c47f2189cc608a78d5b6ee64 --- /dev/null +++ b/components/drivers/tty/tty.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 +#include +#include +#include +#include +#include +#include +#if defined(RT_USING_POSIX) +#include +#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 + +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(¤t->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); + + 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; +} diff --git a/components/drivers/tty/tty_ioctl.c b/components/drivers/tty/tty_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..62b1c7732db03ec33cc1b3cc8d3fcd8e5ac41df2 --- /dev/null +++ b/components/drivers/tty/tty_ioctl.c @@ -0,0 +1,104 @@ +#include +#include +#include +#if defined(RT_USING_POSIX) +#include +#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 + +/* + * 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; +} diff --git a/components/drivers/tty/tty_ldisc.c b/components/drivers/tty/tty_ldisc.c new file mode 100644 index 0000000000000000000000000000000000000000..350a297760e26c17fcac60400544bdb18ce0ad61 --- /dev/null +++ b/components/drivers/tty/tty_ldisc.c @@ -0,0 +1,178 @@ +#include +#include + +#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 + +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; +} diff --git a/components/finsh/shell.c b/components/finsh/shell.c index dbf285ae86f17d7f18b01499beaf1378d1963a8c..3e110408ba3144da6535f3d181e0d73828219da4 100644 --- a/components/finsh/shell.c +++ b/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; } diff --git a/components/libc/Kconfig b/components/libc/Kconfig index 1379e6a40832113acf2e5949093c3aa8fe895806..ae8131703d941f4d18d0a5fcf863c902dfd2df47 100644 --- a/components/libc/Kconfig +++ b/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 diff --git a/components/libc/termios/SConscript b/components/libc/termios/SConscript deleted file mode 100644 index 381eb5ad8bba4e86e55f5800e6ed258dadaf9348..0000000000000000000000000000000000000000 --- a/components/libc/termios/SConscript +++ /dev/null @@ -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') diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index 26aa5762b1547f3e54a518a87cfb2dc041c42ba4..d230167ecac861ec68d52bfdcdafb1d17e7dd196 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -16,13 +16,14 @@ #include #include -#include #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); diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index ef8c6dfdfb4a5433086ab9b547cf140f477034dd..99db3f0363a1da6321a10f278d591ae2bbd6a928 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -41,7 +41,9 @@ #ifdef RT_USING_MUSL #include -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 diff --git a/components/lwp/lwp_console.h b/components/lwp/lwp_console.h deleted file mode 100644 index 5b1702650769ffb313440d09be4109a269224ae9..0000000000000000000000000000000000000000 --- a/components/lwp/lwp_console.h +++ /dev/null @@ -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 -#include -#include - -#include -#include - -#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__*/ diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index e99cdc37d355a239c651711af30690c56429b913..94962a7febf99c30b9fb0b04311b641673b54df2 100644 --- a/components/lwp/lwp_pid.c +++ b/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) diff --git a/components/lwp/lwp_setsid.c b/components/lwp/lwp_setsid.c new file mode 100644 index 0000000000000000000000000000000000000000..d72363bde56a4e8d6c15e2658b7c33ac890c5ada --- /dev/null +++ b/components/lwp/lwp_setsid.c @@ -0,0 +1,27 @@ +#include +#include + +#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; +} diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index a8705c6cd38f8e74fef5650114c62bc258c733f9..18013d0c9270cde0b25143bdf2e1cbe997af76d2 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -54,7 +54,7 @@ #include #endif /* RT_USING_SAL */ -#include +#include #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) diff --git a/components/lwp/unix98pty/lwp_ptmx.c b/components/lwp/unix98pty/lwp_ptmx.c deleted file mode 100644 index 2a857c204fe17be942c3c675133baf3b24ff3705..0000000000000000000000000000000000000000 --- a/components/lwp/unix98pty/lwp_ptmx.c +++ /dev/null @@ -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); diff --git a/components/lwp/unix98pty/lwp_pts.c b/components/lwp/unix98pty/lwp_pts.c deleted file mode 100644 index fc16d761c476a02aa5c638633422998a074d5c6d..0000000000000000000000000000000000000000 --- a/components/lwp/unix98pty/lwp_pts.c +++ /dev/null @@ -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 -#include -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.); diff --git a/components/lwp/unix98pty/lwp_pty.h b/components/lwp/unix98pty/lwp_pty.h deleted file mode 100644 index 7a78259c476b6f7b203769c1f41cb0f9fd10fa7f..0000000000000000000000000000000000000000 --- a/components/lwp/unix98pty/lwp_pty.h +++ /dev/null @@ -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 -#include -#include -#include - -#if defined(RT_USING_POSIX_TERMIOS) -#include -#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 - -#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__ */ diff --git a/include/libc/libc_errno.h b/include/libc/libc_errno.h index d34a143faede30970bf6f352928ef08966f9a877..c5471c51b99428173f2db7b8a5d9771532e2c93e 100644 --- a/include/libc/libc_errno.h +++ b/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 +#define ENOIOCTLCMD (ERROR_BASE_NO + 515) /* No ioctl command */ #endif #if defined(__CC_ARM) diff --git a/src/kservice.c b/src/kservice.c index a19852d4c39361bb09ff5d44096b98ed11f21b97..531a18f9b687fde81349074e95baa42276aa602c 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -29,7 +29,7 @@ #ifdef RT_USING_LWP #include #include -#include +#include #endif /* use precision */ @@ -1132,18 +1132,19 @@ rt_device_t rt_console_set_device(const char *name) { #ifdef RT_USING_LWP rt_device_t new_iodev, 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); }