/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021.12.07 linzhenxing first version */ #ifndef __TTY_H__ #define __TTY_H__ #include #include #include #ifdef RT_USING_LWP #include #endif #if defined(RT_USING_POSIX_TERMIOS) #include #include #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 */ #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__*/