import RT-Thread@9217865c without bsp, libcpu and components/net
This commit is contained in:
commit
e2376a3709
1414 changed files with 390370 additions and 0 deletions
10
components/drivers/tty/SConscript
Normal file
10
components/drivers/tty/SConscript
Normal file
|
@ -0,0 +1,10 @@
|
|||
from building import *
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
src = Glob('*.c')
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + "/include"]
|
||||
|
||||
group = DefineGroup('tty', src, depend = ['RT_USING_SMART', 'RT_USING_TTY'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
297
components/drivers/tty/console.c
Normal file
297
components/drivers/tty/console.c
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <tty.h>
|
||||
|
||||
#define DBG_TAG "CONSOLE"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct tty_struct console_dev;
|
||||
|
||||
static void console_rx_notify(struct rt_device *dev)
|
||||
{
|
||||
struct tty_struct *console = NULL;
|
||||
int len = 0;
|
||||
int lens = 0;
|
||||
char ch = 0;
|
||||
char buf[1024] = {0};
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
len = rt_device_read(console->io_dev, -1, &ch, 1);
|
||||
if (len == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lens += len;
|
||||
buf[lens-1] = ch;
|
||||
if (lens > 1024)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (console->ldisc->ops->receive_buf)
|
||||
{
|
||||
console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens);
|
||||
}
|
||||
}
|
||||
|
||||
struct tty_struct *console_tty_get(void)
|
||||
{
|
||||
return &console_dev;
|
||||
}
|
||||
|
||||
static void iodev_close(struct tty_struct *console)
|
||||
{
|
||||
struct rt_device_notify rx_notify;
|
||||
|
||||
rx_notify.notify = RT_NULL;
|
||||
rx_notify.dev = RT_NULL;
|
||||
|
||||
/* clear notify */
|
||||
rt_device_control(console->io_dev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
|
||||
rt_device_close(console->io_dev);
|
||||
}
|
||||
|
||||
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->io_dev, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
|
||||
|
||||
ret = rt_device_open(console->io_dev, oflags);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rx_notify.notify = console_rx_notify;
|
||||
rx_notify.dev = (struct rt_device *)console;
|
||||
rt_device_control(console->io_dev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
struct rt_device *console_get_iodev(void)
|
||||
{
|
||||
rt_base_t level = 0;
|
||||
struct rt_device *iodev = RT_NULL;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
iodev = console_dev.io_dev;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return iodev;
|
||||
}
|
||||
|
||||
struct rt_device *console_set_iodev(struct rt_device *iodev)
|
||||
{
|
||||
rt_base_t level = 0;
|
||||
struct rt_device *io_before = RT_NULL;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
RT_ASSERT(iodev != RT_NULL);
|
||||
|
||||
console = &console_dev;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
RT_ASSERT(console->init_flag >= TTY_INIT_FLAG_REGED);
|
||||
|
||||
io_before = console->io_dev;
|
||||
if (iodev == io_before)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (console->init_flag >= TTY_INIT_FLAG_INITED)
|
||||
{
|
||||
/* close old device */
|
||||
iodev_close(console);
|
||||
}
|
||||
|
||||
console->io_dev = iodev;
|
||||
if (console->init_flag >= TTY_INIT_FLAG_INITED)
|
||||
{
|
||||
rt_err_t ret;
|
||||
/* open new device */
|
||||
ret = iodev_open(console);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
}
|
||||
|
||||
exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
return io_before;
|
||||
}
|
||||
|
||||
/* RT-Thread Device Interface */
|
||||
/*
|
||||
* This function initializes console device.
|
||||
*/
|
||||
static rt_err_t rt_console_init(struct rt_device *dev)
|
||||
{
|
||||
rt_base_t level = 0;
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_REGED);
|
||||
|
||||
result = iodev_open(console);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
console->init_flag = TTY_INIT_FLAG_INITED;
|
||||
exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_console_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_console_close(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_console_read(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_console_write(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
|
||||
len = rt_device_write((struct rt_device *)console->io_dev, -1, buffer, size);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_err_t rt_console_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
|
||||
len = rt_device_control((struct rt_device *)console->io_dev, cmd, args);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops console_ops =
|
||||
{
|
||||
rt_console_init,
|
||||
rt_console_open,
|
||||
rt_console_close,
|
||||
rt_console_read,
|
||||
rt_console_write,
|
||||
rt_console_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* console register
|
||||
*/
|
||||
static struct dfs_file_ops con_fops;
|
||||
rt_err_t console_register(const char *name, struct rt_device *iodev)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device *device = RT_NULL;
|
||||
struct tty_struct *console = &console_dev;
|
||||
|
||||
RT_ASSERT(iodev != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_NONE);
|
||||
|
||||
tty_init(console, TTY_DRIVER_TYPE_CONSOLE, SERIAL_TYPE_NORMAL, iodev);
|
||||
console_ldata_init(console);
|
||||
|
||||
device = &(console->parent);
|
||||
device->type = RT_Device_Class_Char;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &console_ops;
|
||||
#else
|
||||
device->init = rt_console_init;
|
||||
device->open = rt_console_open;
|
||||
device->close = rt_console_close;
|
||||
device->read = rt_console_read;
|
||||
device->write = rt_console_write;
|
||||
device->control = rt_console_control;
|
||||
#endif
|
||||
|
||||
/* register a character device */
|
||||
ret = rt_device_register(device, name, 0);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("console driver register fail\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
memcpy(&con_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
|
||||
device->fops = &con_fops;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
19
components/drivers/tty/include/console.h
Normal file
19
components/drivers/tty/include/console.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#ifndef __CONSOLE_
|
||||
#define __CONSOLE_
|
||||
#include <rtthread.h>
|
||||
#include "tty.h"
|
||||
|
||||
struct tty_struct *console_tty_get(void);
|
||||
struct rt_device *console_get_iodev(void);
|
||||
struct rt_device *console_set_iodev(struct rt_device *iodev);
|
||||
rt_err_t console_register(const char *name, struct rt_device *iodev);
|
||||
#endif
|
303
components/drivers/tty/include/tty.h
Normal file
303
components/drivers/tty/include/tty.h
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#ifndef __TTY_H__
|
||||
#define __TTY_H__
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <tty_ldisc.h>
|
||||
#ifdef RT_USING_SMART
|
||||
#include <lwp.h>
|
||||
#endif
|
||||
#if defined(RT_USING_POSIX_TERMIOS)
|
||||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#ifndef ENOIOCTLCMD
|
||||
#define ENOIOCTLCMD (515) /* No ioctl command */
|
||||
#endif
|
||||
|
||||
#define current lwp_self()
|
||||
#define __DISABLED_CHAR '\0'
|
||||
|
||||
struct tty_node
|
||||
{
|
||||
struct rt_lwp *lwp;
|
||||
struct tty_node *next;
|
||||
};
|
||||
|
||||
void tty_initstack(struct tty_node *node);
|
||||
int tty_push(struct tty_node **head, struct rt_lwp *lwp);
|
||||
struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp);
|
||||
/*
|
||||
* 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 termios init_termios;
|
||||
struct winsize winsize;
|
||||
struct rt_mutex lock;
|
||||
pid_t pgrp;
|
||||
pid_t session;
|
||||
struct rt_lwp *foreground;
|
||||
struct tty_node *head;
|
||||
|
||||
struct tty_ldisc *ldisc;
|
||||
void *disc_data;
|
||||
struct rt_device *io_dev;
|
||||
|
||||
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
|
||||
|
||||
#define NR_LDISCS 30
|
||||
|
||||
/* line disciplines */
|
||||
#define N_TTY 0
|
||||
#define N_SLIP 1
|
||||
#define N_MOUSE 2
|
||||
#define N_PPP 3
|
||||
#define N_STRIP 4
|
||||
#define N_AX25 5
|
||||
#define N_X25 6 /* X.25 async */
|
||||
#define N_6PACK 7
|
||||
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
|
||||
#define N_R3964 9 /* Reserved for Simatic R3964 module */
|
||||
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */
|
||||
#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */
|
||||
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data */
|
||||
/* cards about SMS messages */
|
||||
#define N_HDLC 13 /* synchronous HDLC */
|
||||
#define N_SYNC_PPP 14 /* synchronous PPP */
|
||||
#define N_HCI 15 /* Bluetooth HCI UART */
|
||||
#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
|
||||
#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
|
||||
#define N_PPS 18 /* Pulse per Second */
|
||||
#define N_V253 19 /* Codec control over voice modem */
|
||||
#define N_CAIF 20 /* CAIF protocol for talking to modems */
|
||||
#define N_GSM0710 21 /* GSM 0710 Mux */
|
||||
#define N_TI_WL 22 /* for TI's WL BT, FM, GPS combo chips */
|
||||
#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
|
||||
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
|
||||
#define N_NCI 25 /* NFC NCI UART */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TIOCPKT_DATA 0
|
||||
#define TIOCPKT_FLUSHREAD 1
|
||||
#define TIOCPKT_FLUSHWRITE 2
|
||||
#define TIOCPKT_STOP 4
|
||||
#define TIOCPKT_START 8
|
||||
#define TIOCPKT_NOSTOP 16
|
||||
#define TIOCPKT_DOSTOP 32
|
||||
|
||||
/* 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 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);
|
||||
}
|
||||
|
||||
int tty_init(struct tty_struct *tty, int type, int subtype, struct rt_device *iodev);
|
||||
const struct dfs_file_ops *tty_get_fops(void);
|
||||
|
||||
int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *arg);
|
||||
|
||||
void console_ldata_init(struct tty_struct *tty);
|
||||
int n_tty_receive_buf(struct tty_struct *tty, char *cp, int count);
|
||||
|
||||
#endif /*__TTY_H__*/
|
56
components/drivers/tty/include/tty_ldisc.h
Normal file
56
components/drivers/tty/include/tty_ldisc.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#ifndef __TTY_LDISC_
|
||||
#define __TTY_LDISC_
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <tty.h>
|
||||
#if defined(RT_USING_POSIX_TERMIOS)
|
||||
#include <termios.h>
|
||||
#endif
|
||||
struct tty_struct;
|
||||
|
||||
struct tty_ldisc_ops
|
||||
{
|
||||
char *name;
|
||||
int num;
|
||||
|
||||
int (*open) (struct dfs_file *fd);
|
||||
int (*close) (struct tty_struct *tty);
|
||||
int (*ioctl) (struct dfs_file *fd, int cmd, void *args);
|
||||
int (*read) (struct dfs_file *fd, void *buf, size_t count);
|
||||
int (*write) (struct dfs_file *fd, const void *buf, size_t count);
|
||||
int (*flush) (struct dfs_file *fd);
|
||||
int (*lseek) (struct dfs_file *fd, off_t offset);
|
||||
int (*getdents) (struct dfs_file *fd, struct dirent *dirp, uint32_t count);
|
||||
|
||||
int (*poll) (struct dfs_file *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_
|
2203
components/drivers/tty/n_tty.c
Normal file
2203
components/drivers/tty/n_tty.c
Normal file
File diff suppressed because it is too large
Load diff
334
components/drivers/tty/pty.c
Normal file
334
components/drivers/tty/pty.c
Normal file
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <tty.h>
|
||||
#include <tty_ldisc.h>
|
||||
|
||||
#define DBG_TAG "PTY"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define PTY_PTS_SIZE 10
|
||||
static struct tty_struct ptm_dev;
|
||||
static struct tty_struct pts_devs[PTY_PTS_SIZE];
|
||||
static int pts_index = 0;
|
||||
|
||||
static int pts_register(struct tty_struct *ptmx, struct tty_struct *pts, 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_devs[i].init_flag == TTY_INIT_FLAG_NONE)
|
||||
{
|
||||
pts_devs[i].init_flag = TTY_INIT_FLAG_ALLOCED;
|
||||
return &pts_devs[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_ubase_t level = 0;
|
||||
rt_err_t result = RT_EOK;
|
||||
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_ssize_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_ssize_t pty_device_write(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
rt_base_t level = 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_file *fd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tty_struct *tty = RT_NULL;
|
||||
struct tty_struct *pts = 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->vnode->data;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
|
||||
pts = find_freepts();
|
||||
if (pts == RT_NULL)
|
||||
{
|
||||
LOG_E("No free PTS device found.\n");
|
||||
return -1;
|
||||
}
|
||||
ret = pts_register(tty, pts, pts_index);
|
||||
if (ret < 0)
|
||||
{
|
||||
LOG_E("pts register fail\n");
|
||||
rt_free(pts);
|
||||
return -1;
|
||||
}
|
||||
pts_index++;
|
||||
lwp = lwp_self();
|
||||
wq = wait_queue_get(lwp, tty);
|
||||
pts->wait_queue = *wq;
|
||||
tty->other_struct = pts;
|
||||
|
||||
ld = tty->ldisc;
|
||||
if (ld->ops->open)
|
||||
{
|
||||
ret = ld->ops->open(fd);
|
||||
}
|
||||
|
||||
rt_device_t device = (rt_device_t)fd->vnode->data;
|
||||
if(fd->vnode->ref_count == 1)
|
||||
{
|
||||
ret = rt_device_open(device, fd->flags);
|
||||
}
|
||||
|
||||
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 *ptmx, struct tty_struct *pts, int pts_index)
|
||||
{
|
||||
char name[20];
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device *device = RT_NULL;
|
||||
|
||||
RT_ASSERT(ptmx!=RT_NULL);
|
||||
|
||||
if (pts->init_flag != TTY_INIT_FLAG_ALLOCED)
|
||||
{
|
||||
LOG_E("pts%d has been registered\n", pts_index);
|
||||
ret = (-RT_EBUSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
tty_init(pts, TTY_DRIVER_TYPE_PTY, PTY_TYPE_SLAVE, NULL);
|
||||
pts->index = pts_index;
|
||||
pts->pts_lock = 1;
|
||||
pts->other_struct = ptmx;
|
||||
|
||||
device = &pts->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;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
memcpy(&pts_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
|
||||
device->fops = &pts_fops;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ptmx_register(void)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device *device = RT_NULL;
|
||||
struct tty_struct *ptmx = &ptm_dev;
|
||||
|
||||
RT_ASSERT(ptmx->init_flag == TTY_INIT_FLAG_NONE);
|
||||
|
||||
tty_init(ptmx, TTY_DRIVER_TYPE_PTY, PTY_TYPE_MASTER, NULL);
|
||||
|
||||
device = &(ptmx->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;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
memcpy(&ptmx_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
|
||||
ptmx_fops.open = ptmx_open;
|
||||
device->fops = &ptmx_fops;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(ptmx_register);
|
440
components/drivers/tty/tty.c
Normal file
440
components/drivers/tty/tty.c
Normal file
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <lwp.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rtthread.h>
|
||||
#include <tty.h>
|
||||
#include <tty_ldisc.h>
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO)
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "TTY"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
const 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
|
||||
};
|
||||
|
||||
void tty_initstack(struct tty_node *node)
|
||||
{
|
||||
node->lwp = RT_NULL;
|
||||
node->next = node;
|
||||
}
|
||||
|
||||
static struct tty_node tty_node_cache = { RT_NULL, RT_NULL };
|
||||
|
||||
static struct tty_node *_tty_node_alloc(void)
|
||||
{
|
||||
struct tty_node *node = tty_node_cache.next;
|
||||
|
||||
if (node == RT_NULL)
|
||||
{
|
||||
node = rt_calloc(1, sizeof(struct tty_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
tty_node_cache.next = node->next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void _tty_node_free(struct tty_node *node)
|
||||
{
|
||||
node->next = tty_node_cache.next;
|
||||
tty_node_cache.next = node;
|
||||
}
|
||||
|
||||
int tty_push(struct tty_node **head, struct rt_lwp *lwp)
|
||||
{
|
||||
struct tty_node *node = _tty_node_alloc();
|
||||
|
||||
if (!node)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->lwp = lwp;
|
||||
node->next = *head;
|
||||
*head = node;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp)
|
||||
{
|
||||
struct tty_node *node;
|
||||
struct rt_lwp *lwp = RT_NULL;
|
||||
|
||||
if (!head || !*head)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
node = *head;
|
||||
|
||||
if (target_lwp != RT_NULL && node->lwp != target_lwp)
|
||||
{
|
||||
struct tty_node *prev = RT_NULL;
|
||||
|
||||
while (node != RT_NULL && node->lwp != target_lwp)
|
||||
{
|
||||
prev = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (node != RT_NULL)
|
||||
{
|
||||
/* prev is impossible equ RT_NULL */
|
||||
prev->next = node->next;
|
||||
lwp = target_lwp;
|
||||
_tty_node_free(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lwp = (*head)->lwp;
|
||||
*head = (*head)->next;
|
||||
node->lwp = RT_NULL;
|
||||
_tty_node_free(node);
|
||||
}
|
||||
|
||||
return lwp;
|
||||
}
|
||||
|
||||
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_mask, 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (current->tty != tty)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
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("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_file *fd)
|
||||
{
|
||||
int ret = 0;
|
||||
int noctty = 0;
|
||||
struct tty_struct *tty = RT_NULL;
|
||||
struct tty_ldisc *ld = RT_NULL;
|
||||
|
||||
tty = (struct tty_struct *)fd->vnode->data;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
|
||||
ld = tty->ldisc;
|
||||
if (ld->ops->open)
|
||||
{
|
||||
ret = ld->ops->open(fd);
|
||||
}
|
||||
noctty = (fd->flags & O_NOCTTY);
|
||||
|
||||
rt_device_t device = (rt_device_t)fd->vnode->data;
|
||||
if (fd->vnode->ref_count == 1)
|
||||
{
|
||||
ret = rt_device_open(device, fd->flags);
|
||||
}
|
||||
if (current == RT_NULL) //kernel mode not lwp
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!noctty &&
|
||||
current->leader &&
|
||||
!current->tty &&
|
||||
tty->session == -1)
|
||||
{
|
||||
current->tty = tty;
|
||||
current->tty_old_pgrp = 0;
|
||||
tty->session = current->session;
|
||||
tty->pgrp = current->__pgrp;
|
||||
tty->foreground = current;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tty_close(struct dfs_file *fd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tty_struct *tty = RT_NULL;
|
||||
struct tty_ldisc *ld = RT_NULL;
|
||||
tty = (struct tty_struct *)fd->vnode->data;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
ld = tty->ldisc;
|
||||
if (ld->ops->close)
|
||||
{
|
||||
//ld->ops->close(tty);
|
||||
}
|
||||
if (fd->vnode->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_file *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->vnode->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_file *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->vnode->data;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
|
||||
ld = tty->ldisc;
|
||||
if (ld && ld->ops->read)
|
||||
{
|
||||
ret = ld->ops->read(fd, buf, count);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tty_write(struct dfs_file *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->vnode->data;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
|
||||
ld = tty->ldisc;
|
||||
if (ld && ld->ops->write)
|
||||
{
|
||||
ret = ld->ops->write(fd, buf, count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tty_poll(struct dfs_file *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->vnode->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,
|
||||
};
|
||||
|
||||
const struct dfs_file_ops *tty_get_fops(void)
|
||||
{
|
||||
return &tty_fops;
|
||||
}
|
||||
|
||||
int tty_init(struct tty_struct *tty, int type, int subtype, struct rt_device *iodev)
|
||||
{
|
||||
if (tty)
|
||||
{
|
||||
struct tty_node *node = NULL;
|
||||
|
||||
node = rt_calloc(1, sizeof(struct tty_node));
|
||||
if (node)
|
||||
{
|
||||
tty->type = type;
|
||||
tty->subtype = subtype;
|
||||
tty->io_dev = iodev;
|
||||
|
||||
tty->head = node;
|
||||
tty_initstack(tty->head);
|
||||
|
||||
tty->pgrp = -1;
|
||||
tty->session = -1;
|
||||
tty->foreground = RT_NULL;
|
||||
|
||||
rt_mutex_init(&tty->lock, "ttyLock", RT_IPC_FLAG_PRIO);
|
||||
rt_wqueue_init(&tty->wait_queue);
|
||||
|
||||
tty_ldisc_init(tty);
|
||||
tty->init_termios = tty_std_termios;
|
||||
tty->init_flag = TTY_INIT_FLAG_REGED;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
109
components/drivers/tty/tty_ioctl.c
Normal file
109
components/drivers/tty/tty_ioctl.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include <stddef.h>
|
||||
#include <rtthread.h>
|
||||
#include <tty.h>
|
||||
#if defined(RT_USING_POSIX_DEVIO)
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "TTY_IOCTL"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* Internal flag options for termios setting behavior
|
||||
*/
|
||||
#define TERMIOS_FLUSH 1
|
||||
#define TERMIOS_WAIT 2
|
||||
#define TERMIOS_TERMIO 4
|
||||
#define TERMIOS_OLD 8
|
||||
|
||||
/**
|
||||
* set_termios - set termios values for a tty
|
||||
* @tty: terminal device
|
||||
* @arg: user data
|
||||
* @opt: option information
|
||||
*
|
||||
* Helper function to prepare termios data and run necessary other
|
||||
* functions before using tty_set_termios to do the actual changes.
|
||||
*
|
||||
* Locking:
|
||||
* Called functions take ldisc and termios_rwsem locks
|
||||
*/
|
||||
|
||||
static int set_termios(struct tty_struct *tty, void *arg, int opt)
|
||||
{
|
||||
struct termios old_termios;
|
||||
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;
|
||||
}
|
||||
|
||||
rt_memcpy(&old_termios, &(tty->init_termios), sizeof(struct termios));
|
||||
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;
|
||||
}
|
179
components/drivers/tty/tty_ldisc.c
Normal file
179
components/drivers/tty/tty_ldisc.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
#include <tty.h>
|
||||
#include <tty_ldisc.h>
|
||||
|
||||
#define DBG_TAG "TTY_LDISC"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
extern struct tty_ldisc_ops n_tty_ops;
|
||||
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS] = {
|
||||
&n_tty_ops, /* N_TTY = 0 */
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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 && 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 && tty->ldisc)
|
||||
{
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
if (tty)
|
||||
{
|
||||
tty->ldisc = tty_ldisc_get(tty, N_TTY);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue