summaryrefslogtreecommitdiff
path: root/components/drivers/tty/include/tty.h
blob: 6a966262a9879481cf0fb73d30c18fd5490e5ae7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
/*
 * 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 <[email protected]> */
#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__*/