2 * linux/drivers/char/tty_ioctl.c
4 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
6 * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
7 * which can be dynamically activated and de-activated by the line
8 * discipline handling modules (like SLIP).
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>
21 #include <linux/module.h>
22 #include <linux/bitops.h>
25 #include <asm/uaccess.h>
26 #include <asm/system.h>
28 #undef TTY_DEBUG_WAIT_UNTIL_SENT
33 * Internal flag options for termios setting behavior
35 #define TERMIOS_FLUSH 1
36 #define TERMIOS_WAIT 2
37 #define TERMIOS_TERMIO 4
41 * tty_wait_until_sent - wait for I/O to finish
42 * @tty: tty we are waiting for
43 * @timeout: how long we will wait
45 * Wait for characters pending in a tty driver to hit the wire, or
46 * for a timeout to occur (eg due to flow control)
51 void tty_wait_until_sent(struct tty_struct
* tty
, long timeout
)
53 DECLARE_WAITQUEUE(wait
, current
);
55 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
58 printk(KERN_DEBUG
"%s wait until sent...\n", tty_name(tty
, buf
));
60 if (!tty
->driver
->chars_in_buffer
)
62 add_wait_queue(&tty
->write_wait
, &wait
);
64 timeout
= MAX_SCHEDULE_TIMEOUT
;
66 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
67 printk(KERN_DEBUG
"waiting %s...(%d)\n", tty_name(tty
, buf
),
68 tty
->driver
->chars_in_buffer(tty
));
70 set_current_state(TASK_INTERRUPTIBLE
);
71 if (signal_pending(current
))
73 if (!tty
->driver
->chars_in_buffer(tty
))
75 timeout
= schedule_timeout(timeout
);
77 if (tty
->driver
->wait_until_sent
)
78 tty
->driver
->wait_until_sent(tty
, timeout
);
80 set_current_state(TASK_RUNNING
);
81 remove_wait_queue(&tty
->write_wait
, &wait
);
84 EXPORT_SYMBOL(tty_wait_until_sent
);
86 static void unset_locked_termios(struct termios
*termios
,
88 struct termios
*locked
)
92 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
95 printk(KERN_WARNING
"Warning?!? termios_locked is NULL.\n");
99 NOSET_MASK(termios
->c_iflag
, old
->c_iflag
, locked
->c_iflag
);
100 NOSET_MASK(termios
->c_oflag
, old
->c_oflag
, locked
->c_oflag
);
101 NOSET_MASK(termios
->c_cflag
, old
->c_cflag
, locked
->c_cflag
);
102 NOSET_MASK(termios
->c_lflag
, old
->c_lflag
, locked
->c_lflag
);
103 termios
->c_line
= locked
->c_line
? old
->c_line
: termios
->c_line
;
104 for (i
=0; i
< NCCS
; i
++)
105 termios
->c_cc
[i
] = locked
->c_cc
[i
] ?
106 old
->c_cc
[i
] : termios
->c_cc
[i
];
110 * change_termios - update termios values
111 * @tty: tty to update
112 * @new_termios: desired new value
114 * Perform updates to the termios values set on this terminal. There
115 * is a bit of layering violation here with n_tty in terms of the
116 * internal knowledge of this function.
118 * Locking: termios_sem
121 static void change_termios(struct tty_struct
* tty
, struct termios
* new_termios
)
124 struct termios old_termios
= *tty
->termios
;
125 struct tty_ldisc
*ld
;
128 * Perform the actual termios internal changes under lock.
132 /* FIXME: we need to decide on some locking/ordering semantics
133 for the set_termios notification eventually */
134 down(&tty
->termios_sem
);
136 *tty
->termios
= *new_termios
;
137 unset_locked_termios(tty
->termios
, &old_termios
, tty
->termios_locked
);
138 canon_change
= (old_termios
.c_lflag
^ tty
->termios
->c_lflag
) & ICANON
;
140 memset(&tty
->read_flags
, 0, sizeof tty
->read_flags
);
141 tty
->canon_head
= tty
->read_tail
;
147 if (canon_change
&& !L_ICANON(tty
) && tty
->read_cnt
)
148 /* Get characters left over from canonical mode. */
149 wake_up_interruptible(&tty
->read_wait
);
151 /* See if packet mode change of state. */
153 if (tty
->link
&& tty
->link
->packet
) {
154 int old_flow
= ((old_termios
.c_iflag
& IXON
) &&
155 (old_termios
.c_cc
[VSTOP
] == '\023') &&
156 (old_termios
.c_cc
[VSTART
] == '\021'));
157 int new_flow
= (I_IXON(tty
) &&
158 STOP_CHAR(tty
) == '\023' &&
159 START_CHAR(tty
) == '\021');
160 if (old_flow
!= new_flow
) {
161 tty
->ctrl_status
&= ~(TIOCPKT_DOSTOP
| TIOCPKT_NOSTOP
);
163 tty
->ctrl_status
|= TIOCPKT_DOSTOP
;
165 tty
->ctrl_status
|= TIOCPKT_NOSTOP
;
166 wake_up_interruptible(&tty
->link
->read_wait
);
170 if (tty
->driver
->set_termios
)
171 (*tty
->driver
->set_termios
)(tty
, &old_termios
);
173 ld
= tty_ldisc_ref(tty
);
176 (ld
->set_termios
)(tty
, &old_termios
);
179 up(&tty
->termios_sem
);
183 * set_termios - set termios values for a tty
184 * @tty: terminal device
186 * @opt: option information
188 * Helper function to prepare termios data and run neccessary other
189 * functions before using change_termios to do the actual changes.
192 * Called functions take ldisc and termios_sem locks
195 static int set_termios(struct tty_struct
* tty
, void __user
*arg
, int opt
)
197 struct termios tmp_termios
;
198 struct tty_ldisc
*ld
;
199 int retval
= tty_check_change(tty
);
204 if (opt
& TERMIOS_TERMIO
) {
205 memcpy(&tmp_termios
, tty
->termios
, sizeof(struct termios
));
206 if (user_termio_to_kernel_termios(&tmp_termios
,
207 (struct termio __user
*)arg
))
210 if (user_termios_to_kernel_termios(&tmp_termios
,
211 (struct termios __user
*)arg
))
215 ld
= tty_ldisc_ref(tty
);
218 if ((opt
& TERMIOS_FLUSH
) && ld
->flush_buffer
)
219 ld
->flush_buffer(tty
);
223 if (opt
& TERMIOS_WAIT
) {
224 tty_wait_until_sent(tty
, 0);
225 if (signal_pending(current
))
229 change_termios(tty
, &tmp_termios
);
233 static int get_termio(struct tty_struct
* tty
, struct termio __user
* termio
)
235 if (kernel_termios_to_user_termio(termio
, tty
->termios
))
240 static unsigned long inq_canon(struct tty_struct
* tty
)
244 if (!tty
->canon_data
|| !tty
->read_buf
)
246 head
= tty
->canon_head
;
247 tail
= tty
->read_tail
;
248 nr
= (head
- tail
) & (N_TTY_BUF_SIZE
-1);
249 /* Skip EOF-chars.. */
250 while (head
!= tail
) {
251 if (test_bit(tail
, tty
->read_flags
) &&
252 tty
->read_buf
[tail
] == __DISABLED_CHAR
)
254 tail
= (tail
+1) & (N_TTY_BUF_SIZE
-1);
261 * These are deprecated, but there is limited support..
263 * The "sg_flags" translation is a joke..
265 static int get_sgflags(struct tty_struct
* tty
)
269 if (!(tty
->termios
->c_lflag
& ICANON
)) {
270 if (tty
->termios
->c_lflag
& ISIG
)
271 flags
|= 0x02; /* cbreak */
273 flags
|= 0x20; /* raw */
275 if (tty
->termios
->c_lflag
& ECHO
)
276 flags
|= 0x08; /* echo */
277 if (tty
->termios
->c_oflag
& OPOST
)
278 if (tty
->termios
->c_oflag
& ONLCR
)
279 flags
|= 0x10; /* crmod */
283 static int get_sgttyb(struct tty_struct
* tty
, struct sgttyb __user
* sgttyb
)
287 down(&tty
->termios_sem
);
290 tmp
.sg_erase
= tty
->termios
->c_cc
[VERASE
];
291 tmp
.sg_kill
= tty
->termios
->c_cc
[VKILL
];
292 tmp
.sg_flags
= get_sgflags(tty
);
293 up(&tty
->termios_sem
);
295 return copy_to_user(sgttyb
, &tmp
, sizeof(tmp
)) ? -EFAULT
: 0;
298 static void set_sgflags(struct termios
* termios
, int flags
)
300 termios
->c_iflag
= ICRNL
| IXON
;
301 termios
->c_oflag
= 0;
302 termios
->c_lflag
= ISIG
| ICANON
;
303 if (flags
& 0x02) { /* cbreak */
304 termios
->c_iflag
= 0;
305 termios
->c_lflag
&= ~ICANON
;
307 if (flags
& 0x08) { /* echo */
308 termios
->c_lflag
|= ECHO
| ECHOE
| ECHOK
|
309 ECHOCTL
| ECHOKE
| IEXTEN
;
311 if (flags
& 0x10) { /* crmod */
312 termios
->c_oflag
|= OPOST
| ONLCR
;
314 if (flags
& 0x20) { /* raw */
315 termios
->c_iflag
= 0;
316 termios
->c_lflag
&= ~(ISIG
| ICANON
);
318 if (!(termios
->c_lflag
& ICANON
)) {
319 termios
->c_cc
[VMIN
] = 1;
320 termios
->c_cc
[VTIME
] = 0;
325 * set_sgttyb - set legacy terminal values
326 * @tty: tty structure
327 * @sgttyb: pointer to old style terminal structure
329 * Updates a terminal from the legacy BSD style terminal information
332 * Locking: termios_sem
335 static int set_sgttyb(struct tty_struct
* tty
, struct sgttyb __user
* sgttyb
)
339 struct termios termios
;
341 retval
= tty_check_change(tty
);
345 if (copy_from_user(&tmp
, sgttyb
, sizeof(tmp
)))
348 down(&tty
->termios_sem
);
349 termios
= *tty
->termios
;
350 termios
.c_cc
[VERASE
] = tmp
.sg_erase
;
351 termios
.c_cc
[VKILL
] = tmp
.sg_kill
;
352 set_sgflags(&termios
, tmp
.sg_flags
);
353 up(&tty
->termios_sem
);
354 change_termios(tty
, &termios
);
360 static int get_tchars(struct tty_struct
* tty
, struct tchars __user
* tchars
)
364 tmp
.t_intrc
= tty
->termios
->c_cc
[VINTR
];
365 tmp
.t_quitc
= tty
->termios
->c_cc
[VQUIT
];
366 tmp
.t_startc
= tty
->termios
->c_cc
[VSTART
];
367 tmp
.t_stopc
= tty
->termios
->c_cc
[VSTOP
];
368 tmp
.t_eofc
= tty
->termios
->c_cc
[VEOF
];
369 tmp
.t_brkc
= tty
->termios
->c_cc
[VEOL2
]; /* what is brkc anyway? */
370 return copy_to_user(tchars
, &tmp
, sizeof(tmp
)) ? -EFAULT
: 0;
373 static int set_tchars(struct tty_struct
* tty
, struct tchars __user
* tchars
)
377 if (copy_from_user(&tmp
, tchars
, sizeof(tmp
)))
379 tty
->termios
->c_cc
[VINTR
] = tmp
.t_intrc
;
380 tty
->termios
->c_cc
[VQUIT
] = tmp
.t_quitc
;
381 tty
->termios
->c_cc
[VSTART
] = tmp
.t_startc
;
382 tty
->termios
->c_cc
[VSTOP
] = tmp
.t_stopc
;
383 tty
->termios
->c_cc
[VEOF
] = tmp
.t_eofc
;
384 tty
->termios
->c_cc
[VEOL2
] = tmp
.t_brkc
; /* what is brkc anyway? */
390 static int get_ltchars(struct tty_struct
* tty
, struct ltchars __user
* ltchars
)
394 tmp
.t_suspc
= tty
->termios
->c_cc
[VSUSP
];
395 tmp
.t_dsuspc
= tty
->termios
->c_cc
[VSUSP
]; /* what is dsuspc anyway? */
396 tmp
.t_rprntc
= tty
->termios
->c_cc
[VREPRINT
];
397 tmp
.t_flushc
= tty
->termios
->c_cc
[VEOL2
]; /* what is flushc anyway? */
398 tmp
.t_werasc
= tty
->termios
->c_cc
[VWERASE
];
399 tmp
.t_lnextc
= tty
->termios
->c_cc
[VLNEXT
];
400 return copy_to_user(ltchars
, &tmp
, sizeof(tmp
)) ? -EFAULT
: 0;
403 static int set_ltchars(struct tty_struct
* tty
, struct ltchars __user
* ltchars
)
407 if (copy_from_user(&tmp
, ltchars
, sizeof(tmp
)))
410 tty
->termios
->c_cc
[VSUSP
] = tmp
.t_suspc
;
411 tty
->termios
->c_cc
[VEOL2
] = tmp
.t_dsuspc
; /* what is dsuspc anyway? */
412 tty
->termios
->c_cc
[VREPRINT
] = tmp
.t_rprntc
;
413 tty
->termios
->c_cc
[VEOL2
] = tmp
.t_flushc
; /* what is flushc anyway? */
414 tty
->termios
->c_cc
[VWERASE
] = tmp
.t_werasc
;
415 tty
->termios
->c_cc
[VLNEXT
] = tmp
.t_lnextc
;
421 * send_prio_char - send priority character
423 * Send a high priority character to the tty even if stopped
427 * FIXME: overlapping calls with start/stop tty lose state of tty
430 static void send_prio_char(struct tty_struct
*tty
, char ch
)
432 int was_stopped
= tty
->stopped
;
434 if (tty
->driver
->send_xchar
) {
435 tty
->driver
->send_xchar(tty
, ch
);
440 tty
->driver
->write(tty
, &ch
, 1);
445 int n_tty_ioctl(struct tty_struct
* tty
, struct file
* file
,
446 unsigned int cmd
, unsigned long arg
)
448 struct tty_struct
* real_tty
;
449 void __user
*p
= (void __user
*)arg
;
451 struct tty_ldisc
*ld
;
453 if (tty
->driver
->type
== TTY_DRIVER_TYPE_PTY
&&
454 tty
->driver
->subtype
== PTY_TYPE_MASTER
)
455 real_tty
= tty
->link
;
462 return get_sgttyb(real_tty
, (struct sgttyb __user
*) arg
);
465 return set_sgttyb(real_tty
, (struct sgttyb __user
*) arg
);
469 return get_tchars(real_tty
, p
);
471 return set_tchars(real_tty
, p
);
475 return get_ltchars(real_tty
, p
);
477 return set_ltchars(real_tty
, p
);
480 if (kernel_termios_to_user_termios((struct termios __user
*)arg
, real_tty
->termios
))
484 return set_termios(real_tty
, p
, TERMIOS_FLUSH
| TERMIOS_WAIT
);
486 return set_termios(real_tty
, p
, TERMIOS_WAIT
);
488 return set_termios(real_tty
, p
, 0);
490 return get_termio(real_tty
, p
);
492 return set_termios(real_tty
, p
, TERMIOS_FLUSH
| TERMIOS_WAIT
| TERMIOS_TERMIO
);
494 return set_termios(real_tty
, p
, TERMIOS_WAIT
| TERMIOS_TERMIO
);
496 return set_termios(real_tty
, p
, TERMIOS_TERMIO
);
498 retval
= tty_check_change(tty
);
503 if (!tty
->flow_stopped
) {
504 tty
->flow_stopped
= 1;
509 if (tty
->flow_stopped
) {
510 tty
->flow_stopped
= 0;
515 if (STOP_CHAR(tty
) != __DISABLED_CHAR
)
516 send_prio_char(tty
, STOP_CHAR(tty
));
519 if (START_CHAR(tty
) != __DISABLED_CHAR
)
520 send_prio_char(tty
, START_CHAR(tty
));
527 retval
= tty_check_change(tty
);
531 ld
= tty_ldisc_ref(tty
);
534 if (ld
&& ld
->flush_buffer
)
535 ld
->flush_buffer(tty
);
538 if (ld
&& ld
->flush_buffer
)
539 ld
->flush_buffer(tty
);
542 if (tty
->driver
->flush_buffer
)
543 tty
->driver
->flush_buffer(tty
);
552 return put_user(tty
->driver
->chars_in_buffer
?
553 tty
->driver
->chars_in_buffer(tty
) : 0,
556 retval
= tty
->read_cnt
;
558 retval
= inq_canon(tty
);
559 return put_user(retval
, (unsigned int __user
*) arg
);
561 if (kernel_termios_to_user_termios((struct termios __user
*)arg
, real_tty
->termios_locked
))
566 if (!capable(CAP_SYS_ADMIN
))
568 if (user_termios_to_kernel_termios(real_tty
->termios_locked
, (struct termios __user
*) arg
))
576 if (tty
->driver
->type
!= TTY_DRIVER_TYPE_PTY
||
577 tty
->driver
->subtype
!= PTY_TYPE_MASTER
)
579 if (get_user(pktmode
, (int __user
*) arg
))
584 tty
->link
->ctrl_status
= 0;
591 return put_user(C_CLOCAL(tty
) ? 1 : 0, (int __user
*)arg
);
593 if (get_user(arg
, (unsigned int __user
*) arg
))
595 down(&tty
->termios_sem
);
596 tty
->termios
->c_cflag
=
597 ((tty
->termios
->c_cflag
& ~CLOCAL
) |
599 up(&tty
->termios_sem
);
606 EXPORT_SYMBOL(n_tty_ioctl
);
This page took 0.071272 seconds and 5 git commands to generate.