This source file includes following definitions.
- tty_wait_until_sent
- unset_locked_termios
- set_termios
- get_termio
- inq_canon
- n_tty_ioctl
1
2
3
4
5
6
7
8
9
10
11 #include <linux/types.h>
12 #include <linux/termios.h>
13 #include <linux/errno.h>
14 #include <linux/sched.h>
15 #include <linux/kernel.h>
16 #include <linux/major.h>
17 #include <linux/tty.h>
18 #include <linux/fcntl.h>
19 #include <linux/string.h>
20 #include <linux/mm.h>
21
22 #include <asm/io.h>
23 #include <asm/bitops.h>
24 #include <asm/segment.h>
25 #include <asm/system.h>
26
27 #undef TTY_DEBUG_WAIT_UNTIL_SENT
28
29 #undef DEBUG
30 #ifdef DEBUG
31 # define PRINTK(x) printk (x)
32 #else
33 # define PRINTK(x)
34 #endif
35
36
37
38
39 #define TERMIOS_FLUSH 1
40 #define TERMIOS_WAIT 2
41 #define TERMIOS_TERMIO 4
42
43 void tty_wait_until_sent(struct tty_struct * tty, int timeout)
44 {
45 struct wait_queue wait = { current, NULL };
46
47 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
48 printk("%s wait until sent...\n", tty_name(tty));
49 #endif
50 if (!tty->driver.chars_in_buffer ||
51 !tty->driver.chars_in_buffer(tty))
52 return;
53 add_wait_queue(&tty->write_wait, &wait);
54 current->counter = 0;
55 if (timeout)
56 current->timeout = timeout + jiffies;
57 else
58 current->timeout = (unsigned) -1;
59 do {
60 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
61 printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty));
62 #endif
63 current->state = TASK_INTERRUPTIBLE;
64 if (current->signal & ~current->blocked)
65 break;
66 if (!tty->driver.chars_in_buffer(tty))
67 break;
68 schedule();
69 } while (current->timeout);
70 current->state = TASK_RUNNING;
71 remove_wait_queue(&tty->write_wait, &wait);
72 }
73
74 static void unset_locked_termios(struct termios *termios,
75 struct termios *old,
76 struct termios *locked)
77 {
78 int i;
79
80 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
81
82 if (!locked) {
83 printk("Warning?!? termios_locked is NULL.\n");
84 return;
85 }
86
87 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
88 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
89 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
90 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
91 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
92 for (i=0; i < NCCS; i++)
93 termios->c_cc[i] = locked->c_cc[i] ?
94 old->c_cc[i] : termios->c_cc[i];
95 }
96
97 static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
98 {
99 struct termio tmp_termio;
100 struct termios tmp_termios;
101 struct termios old_termios = *tty->termios;
102 int retval, canon_change;
103
104 retval = tty_check_change(tty);
105 if (retval)
106 return retval;
107
108 if (opt & TERMIOS_TERMIO) {
109 retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
110 if (retval)
111 return retval;
112 tmp_termios = *tty->termios;
113 memcpy_fromfs(&tmp_termio, (struct termio *) arg,
114 sizeof (struct termio));
115
116 #define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
117 SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
118 SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
119 SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
120 SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
121 memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
122 #undef SET_LOW_BITS
123 } else {
124 retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
125 if (retval)
126 return retval;
127 memcpy_fromfs(&tmp_termios, (struct termios *) arg,
128 sizeof (struct termios));
129 }
130
131 if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
132 tty->ldisc.flush_buffer(tty);
133
134 if (opt & TERMIOS_WAIT)
135 tty_wait_until_sent(tty, 0);
136
137 cli();
138 *tty->termios = tmp_termios;
139 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
140 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
141 if (canon_change) {
142 memset(&tty->read_flags, 0, sizeof tty->read_flags);
143 tty->canon_head = tty->read_tail;
144 tty->canon_data = 0;
145 tty->erasing = 0;
146 }
147 sti();
148 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
149
150 wake_up_interruptible(&tty->read_wait);
151
152
153
154 if (tty->link && tty->link->packet) {
155 int old_flow = ((old_termios.c_iflag & IXON) &&
156 (old_termios.c_cc[VSTOP] == '\023') &&
157 (old_termios.c_cc[VSTART] == '\021'));
158 int new_flow = (I_IXON(tty) &&
159 STOP_CHAR(tty) == '\023' &&
160 START_CHAR(tty) == '\021');
161 if (old_flow != new_flow) {
162 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
163 if (new_flow)
164 tty->ctrl_status |= TIOCPKT_DOSTOP;
165 else
166 tty->ctrl_status |= TIOCPKT_NOSTOP;
167 wake_up_interruptible(&tty->link->read_wait);
168 }
169 }
170
171 if (tty->driver.set_termios)
172 (*tty->driver.set_termios)(tty, &old_termios);
173
174 if (tty->ldisc.set_termios)
175 (*tty->ldisc.set_termios)(tty, &old_termios);
176
177 return 0;
178 }
179
180 static int get_termio(struct tty_struct * tty, struct termio * termio)
181 {
182 int i;
183 struct termio tmp_termio;
184
185 i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
186 if (i)
187 return i;
188 tmp_termio.c_iflag = tty->termios->c_iflag;
189 tmp_termio.c_oflag = tty->termios->c_oflag;
190 tmp_termio.c_cflag = tty->termios->c_cflag;
191 tmp_termio.c_lflag = tty->termios->c_lflag;
192 tmp_termio.c_line = tty->termios->c_line;
193 for(i=0 ; i < NCC ; i++)
194 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
195 memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
196 return 0;
197 }
198
199 static unsigned long inq_canon(struct tty_struct * tty)
200 {
201 int nr, head, tail;
202
203 if (!tty->canon_data || !tty->read_buf)
204 return 0;
205 head = tty->canon_head;
206 tail = tty->read_tail;
207 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
208
209 while (head != tail) {
210 if (test_bit(tail, &tty->read_flags) &&
211 tty->read_buf[tail] == __DISABLED_CHAR)
212 nr--;
213 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
214 }
215 return nr;
216 }
217
218 int n_tty_ioctl(struct tty_struct * tty, struct file * file,
219 unsigned int cmd, unsigned long arg)
220 {
221 struct tty_struct * real_tty;
222 int retval;
223 int opt = 0;
224
225 if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
226 tty->driver.subtype == PTY_TYPE_MASTER)
227 real_tty = tty->link;
228 else
229 real_tty = tty;
230
231 switch (cmd) {
232 case TCGETS:
233 retval = verify_area(VERIFY_WRITE, (void *) arg,
234 sizeof (struct termios));
235 if (retval)
236 return retval;
237 memcpy_tofs((struct termios *) arg,
238 real_tty->termios,
239 sizeof (struct termios));
240 return 0;
241 case TCSETSF:
242 opt |= TERMIOS_FLUSH;
243 case TCSETSW:
244 opt |= TERMIOS_WAIT;
245 case TCSETS:
246 return set_termios(real_tty, arg, opt);
247 case TCGETA:
248 return get_termio(real_tty,(struct termio *) arg);
249 case TCSETAF:
250 opt |= TERMIOS_FLUSH;
251 case TCSETAW:
252 opt |= TERMIOS_WAIT;
253 case TCSETA:
254 return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
255 case TCXONC:
256 retval = tty_check_change(tty);
257 if (retval)
258 return retval;
259 switch (arg) {
260 case TCOOFF:
261 stop_tty(tty);
262 break;
263 case TCOON:
264 start_tty(tty);
265 break;
266 case TCIOFF:
267 if (STOP_CHAR(tty) != __DISABLED_CHAR)
268 tty->driver.write(tty, 0,
269 &STOP_CHAR(tty), 1);
270 break;
271 case TCION:
272 if (START_CHAR(tty) != __DISABLED_CHAR)
273 tty->driver.write(tty, 0,
274 &START_CHAR(tty), 1);
275 break;
276 default:
277 return -EINVAL;
278 }
279 return 0;
280 case TCFLSH:
281 retval = tty_check_change(tty);
282 if (retval)
283 return retval;
284 switch (arg) {
285 case TCIFLUSH:
286 if (tty->ldisc.flush_buffer)
287 tty->ldisc.flush_buffer(tty);
288 break;
289 case TCIOFLUSH:
290 if (tty->ldisc.flush_buffer)
291 tty->ldisc.flush_buffer(tty);
292
293 case TCOFLUSH:
294 if (tty->driver.flush_buffer)
295 tty->driver.flush_buffer(tty);
296 break;
297 default:
298 return -EINVAL;
299 }
300 return 0;
301 case TIOCOUTQ:
302 retval = verify_area(VERIFY_WRITE, (void *) arg,
303 sizeof (int));
304 if (retval)
305 return retval;
306 if (tty->driver.chars_in_buffer)
307 put_user(tty->driver.chars_in_buffer(tty),
308 (int *) arg);
309 else
310 put_user(0, (int *) arg);
311 return 0;
312 case TIOCINQ:
313 retval = verify_area(VERIFY_WRITE, (void *) arg,
314 sizeof (unsigned long));
315 if (retval)
316 return retval;
317 if (L_ICANON(tty))
318 put_fs_long(inq_canon(tty),
319 (unsigned long *) arg);
320 else
321 put_fs_long(tty->read_cnt,
322 (unsigned long *) arg);
323 return 0;
324 case TIOCGLCKTRMIOS:
325 retval = verify_area(VERIFY_WRITE, (void *) arg,
326 sizeof (struct termios));
327 if (retval)
328 return retval;
329 memcpy_tofs((struct termios *) arg,
330 real_tty->termios_locked,
331 sizeof (struct termios));
332 return 0;
333 case TIOCSLCKTRMIOS:
334 if (!suser())
335 return -EPERM;
336 retval = verify_area(VERIFY_READ, (void *) arg,
337 sizeof (struct termios));
338 if (retval)
339 return retval;
340 memcpy_fromfs(real_tty->termios_locked,
341 (struct termios *) arg,
342 sizeof (struct termios));
343 return 0;
344 case TIOCPKT:
345 if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
346 tty->driver.subtype != PTY_TYPE_MASTER)
347 return -ENOTTY;
348 retval = verify_area(VERIFY_READ, (void *) arg,
349 sizeof (int));
350 if (retval)
351 return retval;
352 if (get_user((int*)arg)) {
353 if (!tty->packet) {
354 tty->packet = 1;
355 tty->link->ctrl_status = 0;
356 }
357 } else
358 tty->packet = 0;
359 return 0;
360
361
362 case TCSBRK: case TCSBRKP:
363 retval = tty_check_change(tty);
364 if (retval)
365 return retval;
366 tty_wait_until_sent(tty, 0);
367 if (!tty->driver.ioctl)
368 return 0;
369 tty->driver.ioctl(tty, file, cmd, arg);
370 return 0;
371 default:
372 return -ENOIOCTLCMD;
373 }
374 }