rt-thread/components/drivers/tty/include/tty.h

491 lines
14 KiB
C

/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021.12.07 linzhenxing first version
*/
#ifndef __TTY_H__
#define __TTY_H__
#include <rthw.h>
#include <rtthread.h>
#include <tty_ldisc.h>
#ifdef RT_USING_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 *driver;
struct rt_wqueue wait_queue;
#define RT_TTY_BUF 1024
rt_list_t tty_drivers;
};
enum
{
TTY_INIT_FLAG_NONE = 0,
TTY_INIT_FLAG_ALLOCED,
TTY_INIT_FLAG_REGED,
TTY_INIT_FLAG_INITED,
};
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
#define TTY_DRIVER_TYPE_CONSOLE 0x0002
#define TTY_DRIVER_TYPE_SERIAL 0x0003
#define TTY_DRIVER_TYPE_PTY 0x0004
#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
#define TTY_DRIVER_TYPE_SYSCONS 0x0006
/* tty magic number */
#define TTY_MAGIC 0x5401
/*
* These bits are used in the flags field of the tty structure.
*
* So that interrupts won't be able to mess up the queues,
* copy_to_cooked must be atomic with respect to itself, as must
* tty->write. Thus, you must use the inline functions set_bit() and
* clear_bit() to make things atomic.
*/
#define TTY_THROTTLED 0
#define TTY_IO_ERROR 1
#define TTY_OTHER_CLOSED 2
#define TTY_EXCLUSIVE 3
#define TTY_DEBUG 4
#define TTY_DO_WRITE_WAKEUP 5
#define TTY_PUSH 6
#define TTY_CLOSING 7
#define TTY_DONT_FLIP 8
#define TTY_HW_COOK_OUT 14
#define TTY_HW_COOK_IN 15
#define TTY_PTY_LOCK 16
#define TTY_NO_WRITE_SPLIT 17
/*
* These bits are used in the flags field of the tty structure.
*
* So that interrupts won't be able to mess up the queues,
* copy_to_cooked must be atomic with respect to itself, as must
* tty->write. Thus, you must use the inline functions set_bit() and
* clear_bit() to make things atomic.
*/
#define TTY_THROTTLED 0
#define TTY_IO_ERROR 1
#define TTY_OTHER_CLOSED 2
#define TTY_EXCLUSIVE 3
#define TTY_DEBUG 4
#define TTY_DO_WRITE_WAKEUP 5
#define TTY_PUSH 6
#define TTY_CLOSING 7
#define TTY_DONT_FLIP 8
#define TTY_HW_COOK_OUT 14
#define TTY_HW_COOK_IN 15
#define TTY_PTY_LOCK 16
#define TTY_NO_WRITE_SPLIT 17
#define NR_LDISCS 30
/* line disciplines */
#define N_TTY 0
#define N_SLIP 1
#define N_MOUSE 2
#define N_PPP 3
#define N_STRIP 4
#define N_AX25 5
#define N_X25 6 /* X.25 async */
#define N_6PACK 7
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
#define N_R3964 9 /* Reserved for Simatic R3964 module */
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */
#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data */
/* cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
#define N_SYNC_PPP 14 /* synchronous PPP */
#define N_HCI 15 /* Bluetooth HCI UART */
#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
#define N_PPS 18 /* Pulse per Second */
#define N_V253 19 /* Codec control over voice modem */
#define N_CAIF 20 /* CAIF protocol for talking to modems */
#define N_GSM0710 21 /* GSM 0710 Mux */
#define N_TI_WL 22 /* for TI's WL BT, FM, GPS combo chips */
#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
#define N_NCI 25 /* NFC NCI UART */
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
#define TIOCPKT_FLUSHWRITE 2
#define TIOCPKT_STOP 4
#define TIOCPKT_START 8
#define TIOCPKT_NOSTOP 16
#define TIOCPKT_DOSTOP 32
/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
#define TTY_DRIVER_TYPE_CONSOLE 0x0002
#define TTY_DRIVER_TYPE_SERIAL 0x0003
#define TTY_DRIVER_TYPE_PTY 0x0004
#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
#define TTY_DRIVER_TYPE_SYSCONS 0x0006
/* pty subtypes */
#define PTY_TYPE_MASTER 0x0001
#define PTY_TYPE_SLAVE 0x0002
/* serial subtype definitions */
#define SERIAL_TYPE_NORMAL 1
#define max(a, b) ({\
typeof(a) _a = a;\
typeof(b) _b = b;\
_a > _b ? _a : _b; })
#define min(a, b) ({\
typeof(a) _a = a;\
typeof(b) _b = b;\
_a < _b ? _a : _b; })
void tty_set_fops(struct dfs_file_ops *fops);
void console_set_fops(struct dfs_file_ops *fops);
void mutex_lock(rt_mutex_t mutex);
void mutex_unlock(rt_mutex_t mutex);
int __tty_check_change(struct tty_struct *tty, int sig);
int tty_check_change(struct tty_struct *tty);
rt_inline struct rt_wqueue *wait_queue_get(struct rt_lwp *lwp, struct tty_struct *tty)
{
if (lwp == RT_NULL)
{
return &tty->wait_queue;
}
return &lwp->wait_queue;
}
rt_inline struct rt_wqueue *wait_queue_current_get(struct rt_lwp *lwp, struct tty_struct *tty)
{
return wait_queue_get(lwp, tty);
}
rt_inline void tty_wakeup_check(struct tty_struct *tty)
{
struct rt_wqueue *wq = NULL;
wq = wait_queue_current_get(tty->foreground, tty);
rt_wqueue_wakeup(wq, (void*)POLLIN);
}
rt_inline int set_bit(int nr,int *addr)
{
int mask, retval, level;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
level = rt_hw_interrupt_disable();
retval = (mask & *addr) != 0;
*addr |= mask;
rt_hw_interrupt_enable(level);
return retval;
}
rt_inline int clear_bit(int nr, int *addr)
{
int mask, retval, level;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
level = rt_hw_interrupt_disable();
retval = (mask & *addr) != 0;
*addr &= ~mask;
rt_hw_interrupt_enable(level);
return retval;
}
rt_inline int test_bit(int nr, int *addr)
{
int mask;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
return ((mask & *addr) != 0);
}
rt_inline int test_and_clear_bit(int nr, volatile void *addr)
{
int mask, retval, level;
volatile unsigned int *a = addr;
a += nr >> 5;
mask = 1 << (nr & 0x1f);
level = rt_hw_interrupt_disable();
retval = (mask & *a) != 0;
*a &= ~mask;
rt_hw_interrupt_enable(level);
return retval;
}
rt_inline unsigned long __ffs(unsigned long word)
{
int num = 0;
#if BITS_PER_LONG == 64
if ((word & 0xffffffff) == 0)
{
num += 32;
word >>= 32;
}
#endif
if ((word & 0xffff) == 0)
{
num += 16;
word >>= 16;
}
if ((word & 0xff) == 0)
{
num += 8;
word >>= 8;
}
if ((word & 0xf) == 0)
{
num += 4;
word >>= 4;
}
if ((word & 0x3) == 0)
{
num += 2;
word >>= 2;
}
if ((word & 0x1) == 0)
{
num += 1;
}
return num;
}
#define BITS_PER_LONG 32
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
/*
* Find the next set bit in a memory region.
*/
rt_inline unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
{
return size;
}
size -= result;
offset %= BITS_PER_LONG;
if (offset)
{
tmp = *(p++);
tmp &= (~0UL << offset);
if (size < BITS_PER_LONG)
{
goto found_first;
}
if (tmp)
{
goto found_middle;
}
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1))
{
if ((tmp = *(p++)))
{
goto found_middle;
}
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
{
return result;
}
tmp = *p;
found_first:
tmp &= (~0UL >> (BITS_PER_LONG - size));
if (tmp == 0UL) /* Are any bits set? */
{
return result + size; /* Nope. */
}
found_middle:
return result + __ffs(tmp);
}
/*create by tty_ioctl.c*/
int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *arg);
/*create by n_tty.c*/
void console_ldata_init(struct tty_struct *tty);
int n_tty_receive_buf(struct tty_struct *tty, char *cp, int count);
void n_tty_init(void);
#endif /*__TTY_H__*/