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
|
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_TTY_LDISC_H
#define _LINUX_TTY_LDISC_H
struct tty_struct;
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/atomic.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/seq_file.h>
/*
* the semaphore definition
*/
struct ld_semaphore {
atomic_long_t count;
raw_spinlock_t wait_lock;
unsigned int wait_readers;
struct list_head read_wait;
struct list_head write_wait;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};
void __init_ldsem(struct ld_semaphore *sem, const char *name,
struct lock_class_key *key);
#define init_ldsem(sem) \
do { \
static struct lock_class_key __key; \
\
__init_ldsem((sem), #sem, &__key); \
} while (0)
int ldsem_down_read(struct ld_semaphore *sem, long timeout);
int ldsem_down_read_trylock(struct ld_semaphore *sem);
int ldsem_down_write(struct ld_semaphore *sem, long timeout);
int ldsem_down_write_trylock(struct ld_semaphore *sem);
void ldsem_up_read(struct ld_semaphore *sem);
void ldsem_up_write(struct ld_semaphore *sem);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass,
long timeout);
int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
long timeout);
#else
# define ldsem_down_read_nested(sem, subclass, timeout) \
ldsem_down_read(sem, timeout)
# define ldsem_down_write_nested(sem, subclass, timeout) \
ldsem_down_write(sem, timeout)
#endif
/**
* struct tty_ldisc_ops - ldisc operations
*
* @name: name of this ldisc rendered in /proc/tty/ldiscs
* @num: ``N_*`` number (%N_TTY, %N_HDLC, ...) reserved to this ldisc
*
* @open: [TTY] ``int ()(struct tty_struct *tty)``
*
* This function is called when the line discipline is associated with the
* @tty. No other call into the line discipline for this tty will occur
* until it completes successfully. It should initialize any state needed
* by the ldisc, and set @tty->receive_room to the maximum amount of data
* the line discipline is willing to accept from the driver with a single
* call to @receive_buf(). Returning an error will prevent the ldisc from
* being attached.
*
* Optional. Can sleep.
*
* @close: [TTY] ``void ()(struct tty_struct *tty)``
*
* This function is called when the line discipline is being shutdown,
* either because the @tty is being closed or because the @tty is being
* changed to use a new line discipline. At the point of execution no
* further users will enter the ldisc code for this tty.
*
* Optional. Can sleep.
*
* @flush_buffer: [TTY] ``void ()(struct tty_struct *tty)``
*
* This function instructs the line discipline to clear its buffers of any
* input characters it may have queued to be delivered to the user mode
* process. It may be called at any point between open and close.
*
* Optional.
*
* @read: [TTY] ``ssize_t ()(struct tty_struct *tty, struct file *file, u8 *buf,
* size_t nr)``
*
* This function is called when the user requests to read from the @tty.
* The line discipline will return whatever characters it has buffered up
* for the user. If this function is not defined, the user will receive
* an %EIO error. Multiple read calls may occur in parallel and the ldisc
* must deal with serialization issues.
*
* Optional: %EIO unless provided. Can sleep.
*
* @write: [TTY] ``ssize_t ()(struct tty_struct *tty, struct file *file,
* const u8 *buf, size_t nr)``
*
* This function is called when the user requests to write to the @tty.
* The line discipline will deliver the characters to the low-level tty
* device for transmission, optionally performing some processing on the
* characters first. If this function is not defined, the user will
* receive an %EIO error.
*
* Optional: %EIO unless provided. Can sleep.
*
* @ioctl: [TTY] ``int ()(struct tty_struct *tty, unsigned int cmd,
* unsigned long arg)``
*
* This function is called when the user requests an ioctl which is not
* handled by the tty layer or the low-level tty driver. It is intended
* for ioctls which affect line discpline operation. Note that the search
* order for ioctls is (1) tty layer, (2) tty low-level driver, (3) line
* discpline. So a low-level driver can "grab" an ioctl request before
* the line discpline has a chance to see it.
*
* Optional.
*
* @compat_ioctl: [TTY] ``int ()(struct tty_struct *tty, unsigned int cmd,
* unsigned long arg)``
*
* Process ioctl calls from 32-bit process on 64-bit system.
*
* Note that only ioctls that are neither "pointer to compatible
* structure" nor tty-generic. Something private that takes an integer or
* a pointer to wordsize-sensitive structure belongs here, but most of
* ldiscs will happily leave it %NULL.
*
* Optional.
*
* @set_termios: [TTY] ``void ()(struct tty_struct *tty, const struct ktermios *old)``
*
* This function notifies the line discpline that a change has been made
* to the termios structure.
*
* Optional.
*
* @poll: [TTY] ``int ()(struct tty_struct *tty, struct file *file,
* struct poll_table_struct *wait)``
*
* This function is called when a user attempts to select/poll on a @tty
* device. It is solely the responsibility of the line discipline to
* handle poll requests.
*
* Optional.
*
* @hangup: [TTY] ``void ()(struct tty_struct *tty)``
*
* Called on a hangup. Tells the discipline that it should cease I/O to
* the tty driver. The driver should seek to perform this action quickly
* but should wait until any pending driver I/O is completed. No further
* calls into the ldisc code will occur.
*
* Optional. Can sleep.
*
* @receive_buf: [DRV] ``void ()(struct tty_struct *tty, const u8 *cp,
* const u8 *fp, size_t count)``
*
* This function is called by the low-level tty driver to send characters
* received by the hardware to the line discpline for processing. @cp is
* a pointer to the buffer of input character received by the device. @fp
* is a pointer to an array of flag bytes which indicate whether a
* character was received with a parity error, etc. @fp may be %NULL to
* indicate all data received is %TTY_NORMAL.
*
* Optional.
*
* @write_wakeup: [DRV] ``void ()(struct tty_struct *tty)``
*
* This function is called by the low-level tty driver to signal that line
* discpline should try to send more characters to the low-level driver
* for transmission. If the line discpline does not have any more data to
* send, it can just return. If the line discipline does have some data to
* send, please arise a tasklet or workqueue to do the real data transfer.
* Do not send data in this hook, it may lead to a deadlock.
*
* Optional.
*
* @dcd_change: [DRV] ``void ()(struct tty_struct *tty, bool active)``
*
* Tells the discipline that the DCD pin has changed its status. Used
* exclusively by the %N_PPS (Pulse-Per-Second) line discipline.
*
* Optional.
*
* @receive_buf2: [DRV] ``ssize_t ()(struct tty_struct *tty, const u8 *cp,
* const u8 *fp, size_t count)``
*
* This function is called by the low-level tty driver to send characters
* received by the hardware to the line discpline for processing. @cp is a
* pointer to the buffer of input character received by the device. @fp
* is a pointer to an array of flag bytes which indicate whether a
* character was received with a parity error, etc. @fp may be %NULL to
* indicate all data received is %TTY_NORMAL. If assigned, prefer this
* function for automatic flow control.
*
* Optional.
*
* @lookahead_buf: [DRV] ``void ()(struct tty_struct *tty, const u8 *cp,
* const u8 *fp, size_t count)``
*
* This function is called by the low-level tty driver for characters
* not eaten by ->receive_buf() or ->receive_buf2(). It is useful for
* processing high-priority characters such as software flow-control
* characters that could otherwise get stuck into the intermediate
* buffer until tty has room to receive them. Ldisc must be able to
* handle later a ->receive_buf() or ->receive_buf2() call for the
* same characters (e.g. by skipping the actions for high-priority
* characters already handled by ->lookahead_buf()).
*
* Optional.
*
* @owner: module containting this ldisc (for reference counting)
*
* This structure defines the interface between the tty line discipline
* implementation and the tty routines. The above routines can be defined.
* Unless noted otherwise, they are optional, and can be filled in with a %NULL
* pointer.
*
* Hooks marked [TTY] are invoked from the TTY core, the [DRV] ones from the
* tty_driver side.
*/
struct tty_ldisc_ops {
char *name;
int num;
/*
* The following routines are called from above.
*/
int (*open)(struct tty_struct *tty);
void (*close)(struct tty_struct *tty);
void (*flush_buffer)(struct tty_struct *tty);
ssize_t (*read)(struct tty_struct *tty, struct file *file, u8 *buf,
size_t nr, void **cookie, unsigned long offset);
ssize_t (*write)(struct tty_struct *tty, struct file *file,
const u8 *buf, size_t nr);
int (*ioctl)(struct tty_struct *tty, unsigned int cmd,
unsigned long arg);
int (*compat_ioctl)(struct tty_struct *tty, unsigned int cmd,
unsigned long arg);
void (*set_termios)(struct tty_struct *tty, const struct ktermios *old);
__poll_t (*poll)(struct tty_struct *tty, struct file *file,
struct poll_table_struct *wait);
void (*hangup)(struct tty_struct *tty);
/*
* The following routines are called from below.
*/
void (*receive_buf)(struct tty_struct *tty, const u8 *cp,
const u8 *fp, size_t count);
void (*write_wakeup)(struct tty_struct *tty);
void (*dcd_change)(struct tty_struct *tty, bool active);
size_t (*receive_buf2)(struct tty_struct *tty, const u8 *cp,
const u8 *fp, size_t count);
void (*lookahead_buf)(struct tty_struct *tty, const u8 *cp,
const u8 *fp, size_t count);
struct module *owner;
};
struct tty_ldisc {
struct tty_ldisc_ops *ops;
struct tty_struct *tty;
};
#define MODULE_ALIAS_LDISC(ldisc) \
MODULE_ALIAS("tty-ldisc-" __stringify(ldisc))
extern const struct seq_operations tty_ldiscs_seq_ops;
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
void tty_ldisc_deref(struct tty_ldisc *);
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
void tty_ldisc_flush(struct tty_struct *tty);
int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc);
void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc);
int tty_set_ldisc(struct tty_struct *tty, int disc);
#endif /* _LINUX_TTY_LDISC_H */
|