import RT-Thread@9217865c without bsp, libcpu and components/net

This commit is contained in:
Zihao Yu 2023-05-20 16:23:33 +08:00
commit e2376a3709
1414 changed files with 390370 additions and 0 deletions

View 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')

View 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;
}

View 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

View 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__*/

View 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_

File diff suppressed because it is too large Load diff

View 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);

View 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(&current->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;
}

View 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;
}

View 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);
}
}