blob: 1bdd2bf4f37d74808bd60bcce01e67a2c6d57f5d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/char/tty_ioctl.c
3 *
4 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
5 *
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).
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#include <linux/module.h>
22#include <linux/bitops.h>
Arjan van de Ven5785c952006-09-29 02:00:43 -070023#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#include <asm/io.h>
26#include <asm/uaccess.h>
27#include <asm/system.h>
28
29#undef TTY_DEBUG_WAIT_UNTIL_SENT
30
31#undef DEBUG
32
33/*
34 * Internal flag options for termios setting behavior
35 */
36#define TERMIOS_FLUSH 1
37#define TERMIOS_WAIT 2
38#define TERMIOS_TERMIO 4
Alan Coxedc6afc2006-12-08 02:38:44 -080039#define TERMIOS_OLD 8
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Alan Coxaf9b8972006-08-27 01:24:01 -070041
42/**
43 * tty_wait_until_sent - wait for I/O to finish
44 * @tty: tty we are waiting for
45 * @timeout: how long we will wait
46 *
47 * Wait for characters pending in a tty driver to hit the wire, or
48 * for a timeout to occur (eg due to flow control)
49 *
50 * Locking: none
51 */
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053void tty_wait_until_sent(struct tty_struct * tty, long timeout)
54{
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
56 char buf[64];
57
58 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
59#endif
60 if (!tty->driver->chars_in_buffer)
61 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 if (!timeout)
63 timeout = MAX_SCHEDULE_TIMEOUT;
Jiri Slaby5a52bd42007-07-15 23:40:18 -070064 if (wait_event_interruptible_timeout(tty->write_wait,
65 !tty->driver->chars_in_buffer(tty), timeout))
66 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 if (tty->driver->wait_until_sent)
68 tty->driver->wait_until_sent(tty, timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
71EXPORT_SYMBOL(tty_wait_until_sent);
72
Alan Coxedc6afc2006-12-08 02:38:44 -080073static void unset_locked_termios(struct ktermios *termios,
74 struct ktermios *old,
75 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
77 int i;
78
79#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
80
81 if (!locked) {
82 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
83 return;
84 }
85
86 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
87 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
88 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
89 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
90 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
91 for (i=0; i < NCCS; i++)
92 termios->c_cc[i] = locked->c_cc[i] ?
93 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -080094 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
Alan Coxedc6afc2006-12-08 02:38:44 -080097/*
98 * Routine which returns the baud rate of the tty
99 *
100 * Note that the baud_table needs to be kept in sync with the
101 * include/asm/termbits.h file.
102 */
103static const speed_t baud_table[] = {
104 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
105 9600, 19200, 38400, 57600, 115200, 230400, 460800,
106#ifdef __sparc__
107 76800, 153600, 307200, 614400, 921600
108#else
109 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
110 2500000, 3000000, 3500000, 4000000
111#endif
112};
113
114#ifndef __sparc__
115static const tcflag_t baud_bits[] = {
116 B0, B50, B75, B110, B134, B150, B200, B300, B600,
117 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
118 B57600, B115200, B230400, B460800, B500000, B576000,
119 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
120 B3000000, B3500000, B4000000
121};
122#else
123static const tcflag_t baud_bits[] = {
124 B0, B50, B75, B110, B134, B150, B200, B300, B600,
125 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
126 B57600, B115200, B230400, B460800, B76800, B153600,
127 B307200, B614400, B921600
128};
129#endif
130
131static int n_baud_table = ARRAY_SIZE(baud_table);
132
133/**
134 * tty_termios_baud_rate
135 * @termios: termios structure
136 *
137 * Convert termios baud rate data into a speed. This should be called
138 * with the termios lock held if this termios is a terminal termios
139 * structure. May change the termios data. Device drivers can call this
140 * function but should use ->c_[io]speed directly as they are updated.
141 *
142 * Locking: none
143 */
144
145speed_t tty_termios_baud_rate(struct ktermios *termios)
146{
147 unsigned int cbaud;
148
149 cbaud = termios->c_cflag & CBAUD;
150
151#ifdef BOTHER
152 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
153 if (cbaud == BOTHER)
154 return termios->c_ospeed;
155#endif
156 if (cbaud & CBAUDEX) {
157 cbaud &= ~CBAUDEX;
158
159 if (cbaud < 1 || cbaud + 15 > n_baud_table)
160 termios->c_cflag &= ~CBAUDEX;
161 else
162 cbaud += 15;
163 }
164 return baud_table[cbaud];
165}
166
167EXPORT_SYMBOL(tty_termios_baud_rate);
168
169/**
170 * tty_termios_input_baud_rate
171 * @termios: termios structure
172 *
173 * Convert termios baud rate data into a speed. This should be called
174 * with the termios lock held if this termios is a terminal termios
175 * structure. May change the termios data. Device drivers can call this
176 * function but should use ->c_[io]speed directly as they are updated.
177 *
178 * Locking: none
179 */
180
181speed_t tty_termios_input_baud_rate(struct ktermios *termios)
182{
183#ifdef IBSHIFT
184 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
185
186 if (cbaud == B0)
187 return tty_termios_baud_rate(termios);
188
189 /* Magic token for arbitary speed via c_ispeed*/
190 if (cbaud == BOTHER)
191 return termios->c_ispeed;
192
193 if (cbaud & CBAUDEX) {
194 cbaud &= ~CBAUDEX;
195
196 if (cbaud < 1 || cbaud + 15 > n_baud_table)
197 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
198 else
199 cbaud += 15;
200 }
201 return baud_table[cbaud];
202#else
203 return tty_termios_baud_rate(termios);
204#endif
205}
206
207EXPORT_SYMBOL(tty_termios_input_baud_rate);
208
Alan Coxedc6afc2006-12-08 02:38:44 -0800209/**
210 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800211 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800212 * @ispeed: input speed
213 * @ospeed: output speed
214 *
215 * Encode the speeds set into the passed termios structure. This is
216 * used as a library helper for drivers os that they can report back
217 * the actual speed selected when it differs from the speed requested
218 *
Alan Cox78137e32007-02-10 01:45:57 -0800219 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
220 * we need to carefully set the bits when the user does not get the
221 * desired speed. We allow small margins and preserve as much of possible
222 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800223 *
224 * Locking: Caller should hold termios lock. This is already held
225 * when calling this function from the driver termios handler.
Alan Cox5f519d72007-10-16 23:30:07 -0700226 *
227 * The ifdefs deal with platforms whose owners have yet to update them
228 * and will all go away once this is done.
Alan Coxedc6afc2006-12-08 02:38:44 -0800229 */
230
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700231void tty_termios_encode_baud_rate(struct ktermios *termios,
232 speed_t ibaud, speed_t obaud)
Alan Coxedc6afc2006-12-08 02:38:44 -0800233{
234 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800235 int ifound = -1, ofound = -1;
236 int iclose = ibaud/50, oclose = obaud/50;
237 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800238
Alan Cox5f519d72007-10-16 23:30:07 -0700239 if (obaud == 0) /* CD dropped */
240 ibaud = 0; /* Clear ibaud to be sure */
241
Alan Coxedc6afc2006-12-08 02:38:44 -0800242 termios->c_ispeed = ibaud;
243 termios->c_ospeed = obaud;
244
Alan Cox5f519d72007-10-16 23:30:07 -0700245#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800246 /* If the user asked for a precise weird speed give a precise weird
247 answer. If they asked for a Bfoo speed they many have problems
248 digesting non-exact replies so fuzz a bit */
249
250 if ((termios->c_cflag & CBAUD) == BOTHER)
251 oclose = 0;
252 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
253 iclose = 0;
254 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
255 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700256#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800257 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800258
Alan Cox5f519d72007-10-16 23:30:07 -0700259 /*
260 * Our goal is to find a close match to the standard baud rate
261 * returned. Walk the baud rate table and if we get a very close
262 * match then report back the speed as a POSIX Bxxxx value by
263 * preference
264 */
265
Alan Coxedc6afc2006-12-08 02:38:44 -0800266 do {
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700267 if (obaud - oclose <= baud_table[i] &&
268 obaud + oclose >= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800269 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800270 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800271 }
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700272 if (ibaud - iclose <= baud_table[i] &&
273 ibaud + iclose >= baud_table[i]) {
274 /* For the case input == output don't set IBAUD bits
275 if the user didn't do so */
Alan Cox5f519d72007-10-16 23:30:07 -0700276 if (ofound == i && !ibinput)
277 ifound = i;
278#ifdef IBSHIFT
279 else {
280 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800281 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700282 }
283#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800284 }
Jiri Slaby68043962007-07-15 23:40:18 -0700285 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700286
287 /*
288 * If we found no match then use BOTHER if provided or warn
289 * the user their platform maintainer needs to wake up if not.
290 */
291#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800292 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800293 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800294 /* Set exact input bits only if the input and output differ or the
295 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700296 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800297 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700298#else
299 if (ifound == -1 || ofound == -1) {
300 static int warned;
301 if (!warned++)
302 printk(KERN_WARNING "tty: Unable to return correct "
303 "speed data as your architecture needs updating.\n");
304 }
305#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800306}
Alan Coxedc6afc2006-12-08 02:38:44 -0800307EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
308
Alan Cox5f519d72007-10-16 23:30:07 -0700309void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
310{
311 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
312}
313EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800314
315/**
316 * tty_get_baud_rate - get tty bit rates
317 * @tty: tty to query
318 *
319 * Returns the baud rate as an integer for this terminal. The
320 * termios lock must be held by the caller and the terminal bit
321 * flags may be updated.
322 *
323 * Locking: none
324 */
325
326speed_t tty_get_baud_rate(struct tty_struct *tty)
327{
328 speed_t baud = tty_termios_baud_rate(tty->termios);
329
330 if (baud == 38400 && tty->alt_speed) {
331 if (!tty->warned) {
332 printk(KERN_WARNING "Use of setserial/setrocket to "
333 "set SPD_* flags is deprecated\n");
334 tty->warned = 1;
335 }
336 baud = tty->alt_speed;
337 }
338
339 return baud;
340}
341
342EXPORT_SYMBOL(tty_get_baud_rate);
343
Alan Coxaf9b8972006-08-27 01:24:01 -0700344/**
Alan Cox5f519d72007-10-16 23:30:07 -0700345 * tty_termios_copy_hw - copy hardware settings
346 * @new: New termios
347 * @old: Old termios
348 *
349 * Propogate the hardware specific terminal setting bits from
350 * the old termios structure to the new one. This is used in cases
351 * where the hardware does not support reconfiguration or as a helper
352 * in some cases where only minimal reconfiguration is supported
353 */
354
355void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
356{
357 /* The bits a dumb device handles in software. Smart devices need
358 to always provide a set_termios method */
359 new->c_cflag &= HUPCL | CREAD | CLOCAL;
360 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
361 new->c_ispeed = old->c_ispeed;
362 new->c_ospeed = old->c_ospeed;
363}
364
365EXPORT_SYMBOL(tty_termios_copy_hw);
366
367/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700368 * change_termios - update termios values
369 * @tty: tty to update
370 * @new_termios: desired new value
371 *
372 * Perform updates to the termios values set on this terminal. There
373 * is a bit of layering violation here with n_tty in terms of the
374 * internal knowledge of this function.
375 *
376 * Locking: termios_sem
377 */
378
Alan Coxedc6afc2006-12-08 02:38:44 -0800379static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800382 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 struct tty_ldisc *ld;
384
385 /*
386 * Perform the actual termios internal changes under lock.
387 */
388
389
390 /* FIXME: we need to decide on some locking/ordering semantics
391 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700392 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 *tty->termios = *new_termios;
395 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
396 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
397 if (canon_change) {
398 memset(&tty->read_flags, 0, sizeof tty->read_flags);
399 tty->canon_head = tty->read_tail;
400 tty->canon_data = 0;
401 tty->erasing = 0;
402 }
403
Alan Cox5f519d72007-10-16 23:30:07 -0700404 /* This bit should be in the ldisc code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
406 /* Get characters left over from canonical mode. */
407 wake_up_interruptible(&tty->read_wait);
408
409 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (tty->link && tty->link->packet) {
411 int old_flow = ((old_termios.c_iflag & IXON) &&
412 (old_termios.c_cc[VSTOP] == '\023') &&
413 (old_termios.c_cc[VSTART] == '\021'));
414 int new_flow = (I_IXON(tty) &&
415 STOP_CHAR(tty) == '\023' &&
416 START_CHAR(tty) == '\021');
417 if (old_flow != new_flow) {
418 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
419 if (new_flow)
420 tty->ctrl_status |= TIOCPKT_DOSTOP;
421 else
422 tty->ctrl_status |= TIOCPKT_NOSTOP;
423 wake_up_interruptible(&tty->link->read_wait);
424 }
425 }
426
427 if (tty->driver->set_termios)
428 (*tty->driver->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700429 else
430 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
432 ld = tty_ldisc_ref(tty);
433 if (ld != NULL) {
434 if (ld->set_termios)
435 (ld->set_termios)(tty, &old_termios);
436 tty_ldisc_deref(ld);
437 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700438 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
Alan Coxaf9b8972006-08-27 01:24:01 -0700441/**
442 * set_termios - set termios values for a tty
443 * @tty: terminal device
444 * @arg: user data
445 * @opt: option information
446 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200447 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700448 * functions before using change_termios to do the actual changes.
449 *
450 * Locking:
451 * Called functions take ldisc and termios_sem locks
452 */
453
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
455{
Alan Coxedc6afc2006-12-08 02:38:44 -0800456 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 struct tty_ldisc *ld;
458 int retval = tty_check_change(tty);
459
460 if (retval)
461 return retval;
462
Alan Cox64bb6c52006-12-08 02:38:47 -0800463 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 if (user_termio_to_kernel_termios(&tmp_termios,
467 (struct termio __user *)arg))
468 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800469#ifdef TCGETS2
470 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800471 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 (struct termios __user *)arg))
473 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800474 } else {
475 if (user_termios_to_kernel_termios(&tmp_termios,
476 (struct termios2 __user *)arg))
477 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800479#else
480 } else if (user_termios_to_kernel_termios(&tmp_termios,
481 (struct termios __user *)arg))
482 return -EFAULT;
483#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Alan Coxedc6afc2006-12-08 02:38:44 -0800485 /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
486 so its unconditionally usable */
487 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
488 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 ld = tty_ldisc_ref(tty);
491
492 if (ld != NULL) {
493 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
494 ld->flush_buffer(tty);
495 tty_ldisc_deref(ld);
496 }
497
498 if (opt & TERMIOS_WAIT) {
499 tty_wait_until_sent(tty, 0);
500 if (signal_pending(current))
501 return -EINTR;
502 }
503
504 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700505
506 /* FIXME: Arguably if tmp_termios == tty->termios AND the
507 actual requested termios was not tmp_termios then we may
508 want to return an error as no user requested change has
509 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return 0;
511}
512
513static int get_termio(struct tty_struct * tty, struct termio __user * termio)
514{
515 if (kernel_termios_to_user_termio(termio, tty->termios))
516 return -EFAULT;
517 return 0;
518}
519
520static unsigned long inq_canon(struct tty_struct * tty)
521{
522 int nr, head, tail;
523
524 if (!tty->canon_data || !tty->read_buf)
525 return 0;
526 head = tty->canon_head;
527 tail = tty->read_tail;
528 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
529 /* Skip EOF-chars.. */
530 while (head != tail) {
531 if (test_bit(tail, tty->read_flags) &&
532 tty->read_buf[tail] == __DISABLED_CHAR)
533 nr--;
534 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
535 }
536 return nr;
537}
538
539#ifdef TIOCGETP
540/*
541 * These are deprecated, but there is limited support..
542 *
543 * The "sg_flags" translation is a joke..
544 */
545static int get_sgflags(struct tty_struct * tty)
546{
547 int flags = 0;
548
549 if (!(tty->termios->c_lflag & ICANON)) {
550 if (tty->termios->c_lflag & ISIG)
551 flags |= 0x02; /* cbreak */
552 else
553 flags |= 0x20; /* raw */
554 }
555 if (tty->termios->c_lflag & ECHO)
556 flags |= 0x08; /* echo */
557 if (tty->termios->c_oflag & OPOST)
558 if (tty->termios->c_oflag & ONLCR)
559 flags |= 0x10; /* crmod */
560 return flags;
561}
562
563static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
564{
565 struct sgttyb tmp;
566
Arjan van de Ven5785c952006-09-29 02:00:43 -0700567 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800568 tmp.sg_ispeed = tty->termios->c_ispeed;
569 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 tmp.sg_erase = tty->termios->c_cc[VERASE];
571 tmp.sg_kill = tty->termios->c_cc[VKILL];
572 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700573 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
576}
577
Alan Coxedc6afc2006-12-08 02:38:44 -0800578static void set_sgflags(struct ktermios * termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 termios->c_iflag = ICRNL | IXON;
581 termios->c_oflag = 0;
582 termios->c_lflag = ISIG | ICANON;
583 if (flags & 0x02) { /* cbreak */
584 termios->c_iflag = 0;
585 termios->c_lflag &= ~ICANON;
586 }
587 if (flags & 0x08) { /* echo */
588 termios->c_lflag |= ECHO | ECHOE | ECHOK |
589 ECHOCTL | ECHOKE | IEXTEN;
590 }
591 if (flags & 0x10) { /* crmod */
592 termios->c_oflag |= OPOST | ONLCR;
593 }
594 if (flags & 0x20) { /* raw */
595 termios->c_iflag = 0;
596 termios->c_lflag &= ~(ISIG | ICANON);
597 }
598 if (!(termios->c_lflag & ICANON)) {
599 termios->c_cc[VMIN] = 1;
600 termios->c_cc[VTIME] = 0;
601 }
602}
603
Alan Coxaf9b8972006-08-27 01:24:01 -0700604/**
605 * set_sgttyb - set legacy terminal values
606 * @tty: tty structure
607 * @sgttyb: pointer to old style terminal structure
608 *
609 * Updates a terminal from the legacy BSD style terminal information
610 * structure.
611 *
612 * Locking: termios_sem
613 */
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
616{
617 int retval;
618 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800619 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 retval = tty_check_change(tty);
622 if (retval)
623 return retval;
624
625 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
626 return -EFAULT;
627
Arjan van de Ven5785c952006-09-29 02:00:43 -0700628 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700629 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 termios.c_cc[VERASE] = tmp.sg_erase;
631 termios.c_cc[VKILL] = tmp.sg_kill;
632 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800633 /* Try and encode into Bfoo format */
634#ifdef BOTHER
635 tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
636#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700637 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 change_termios(tty, &termios);
639 return 0;
640}
641#endif
642
643#ifdef TIOCGETC
644static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
645{
646 struct tchars tmp;
647
648 tmp.t_intrc = tty->termios->c_cc[VINTR];
649 tmp.t_quitc = tty->termios->c_cc[VQUIT];
650 tmp.t_startc = tty->termios->c_cc[VSTART];
651 tmp.t_stopc = tty->termios->c_cc[VSTOP];
652 tmp.t_eofc = tty->termios->c_cc[VEOF];
653 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
654 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
655}
656
657static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
658{
659 struct tchars tmp;
660
661 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
662 return -EFAULT;
663 tty->termios->c_cc[VINTR] = tmp.t_intrc;
664 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
665 tty->termios->c_cc[VSTART] = tmp.t_startc;
666 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
667 tty->termios->c_cc[VEOF] = tmp.t_eofc;
668 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
669 return 0;
670}
671#endif
672
673#ifdef TIOCGLTC
674static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
675{
676 struct ltchars tmp;
677
678 tmp.t_suspc = tty->termios->c_cc[VSUSP];
679 tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
680 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
681 tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
682 tmp.t_werasc = tty->termios->c_cc[VWERASE];
683 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
684 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
685}
686
687static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
688{
689 struct ltchars tmp;
690
691 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
692 return -EFAULT;
693
694 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
695 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
696 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
697 tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
698 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
699 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
700 return 0;
701}
702#endif
703
Alan Coxaf9b8972006-08-27 01:24:01 -0700704/**
705 * send_prio_char - send priority character
706 *
707 * Send a high priority character to the tty even if stopped
708 *
Alan Cox5f412b22006-09-29 02:01:40 -0700709 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700711
Alan Cox5f412b22006-09-29 02:01:40 -0700712static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 int was_stopped = tty->stopped;
715
716 if (tty->driver->send_xchar) {
717 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700718 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
Alan Cox5f412b22006-09-29 02:01:40 -0700720
Alan Cox9c1729d2007-07-15 23:39:43 -0700721 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700722 return -ERESTARTSYS;
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (was_stopped)
725 start_tty(tty);
726 tty->driver->write(tty, &ch, 1);
727 if (was_stopped)
728 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700729 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700730 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
Alan Cox0fc00e22007-11-07 01:24:56 -0800733/**
734 * tty_mode_ioctl - mode related ioctls
735 * @tty: tty for the ioctl
736 * @file: file pointer for the tty
737 * @cmd: command
738 * @arg: ioctl argument
739 *
740 * Perform non line discipline specific mode control ioctls. This
741 * is designed to be called by line disciplines to ensure they provide
742 * consistent mode setting.
743 */
744
745int tty_mode_ioctl(struct tty_struct * tty, struct file *file,
746 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747{
748 struct tty_struct * real_tty;
749 void __user *p = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
752 tty->driver->subtype == PTY_TYPE_MASTER)
753 real_tty = tty->link;
754 else
755 real_tty = tty;
756
757 switch (cmd) {
758#ifdef TIOCGETP
759 case TIOCGETP:
760 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
761 case TIOCSETP:
762 case TIOCSETN:
763 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
764#endif
765#ifdef TIOCGETC
766 case TIOCGETC:
767 return get_tchars(real_tty, p);
768 case TIOCSETC:
769 return set_tchars(real_tty, p);
770#endif
771#ifdef TIOCGLTC
772 case TIOCGLTC:
773 return get_ltchars(real_tty, p);
774 case TIOCSLTC:
775 return set_ltchars(real_tty, p);
776#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800777 case TCSETSF:
778 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
779 case TCSETSW:
780 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
781 case TCSETS:
782 return set_termios(real_tty, p, TERMIOS_OLD);
783#ifndef TCGETS2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 case TCGETS:
785 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
786 return -EFAULT;
787 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800788#else
789 case TCGETS:
Alan Cox64bb6c52006-12-08 02:38:47 -0800790 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800791 return -EFAULT;
792 return 0;
793 case TCGETS2:
Alan Cox64bb6c52006-12-08 02:38:47 -0800794 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
Alan Coxedc6afc2006-12-08 02:38:44 -0800795 return -EFAULT;
796 return 0;
797 case TCSETSF2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800799 case TCSETSW2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return set_termios(real_tty, p, TERMIOS_WAIT);
Alan Coxedc6afc2006-12-08 02:38:44 -0800801 case TCSETS2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800803#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 case TCGETA:
805 return get_termio(real_tty, p);
806 case TCSETAF:
807 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
808 case TCSETAW:
809 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
810 case TCSETA:
811 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -0800812#ifndef TCGETS2
813 case TIOCGLCKTRMIOS:
814 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
815 return -EFAULT;
816 return 0;
817
818 case TIOCSLCKTRMIOS:
819 if (!capable(CAP_SYS_ADMIN))
820 return -EPERM;
821 if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
822 return -EFAULT;
823 return 0;
824#else
825 case TIOCGLCKTRMIOS:
826 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
827 return -EFAULT;
828 return 0;
829
830 case TIOCSLCKTRMIOS:
831 if (!capable(CAP_SYS_ADMIN))
832 return -EPERM;
833 if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
834 return -EFAULT;
835 return 0;
836#endif
837 case TIOCGSOFTCAR:
838 return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
839 case TIOCSSOFTCAR:
840 if (get_user(arg, (unsigned int __user *) arg))
841 return -EFAULT;
842 mutex_lock(&tty->termios_mutex);
843 tty->termios->c_cflag =
844 ((tty->termios->c_cflag & ~CLOCAL) |
845 (arg ? CLOCAL : 0));
846 mutex_unlock(&tty->termios_mutex);
847 return 0;
848 default:
849 return -ENOIOCTLCMD;
850 }
851}
852
853EXPORT_SYMBOL_GPL(tty_mode_ioctl);
854
855int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
856{
857 struct tty_ldisc *ld;
858 int retval = tty_check_change(tty);
859 if (retval)
860 return retval;
861
862 ld = tty_ldisc_ref(tty);
863 switch (arg) {
864 case TCIFLUSH:
865 if (ld && ld->flush_buffer)
866 ld->flush_buffer(tty);
867 break;
868 case TCIOFLUSH:
869 if (ld && ld->flush_buffer)
870 ld->flush_buffer(tty);
871 /* fall through */
872 case TCOFLUSH:
873 if (tty->driver->flush_buffer)
874 tty->driver->flush_buffer(tty);
875 break;
876 default:
877 tty_ldisc_deref(ld);
878 return -EINVAL;
879 }
880 tty_ldisc_deref(ld);
881 return 0;
882}
883
884EXPORT_SYMBOL_GPL(tty_perform_flush);
885
886int n_tty_ioctl(struct tty_struct * tty, struct file * file,
887 unsigned int cmd, unsigned long arg)
888{
889 struct tty_struct * real_tty;
890 int retval;
891
892 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
893 tty->driver->subtype == PTY_TYPE_MASTER)
894 real_tty = tty->link;
895 else
896 real_tty = tty;
897
898 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 case TCXONC:
900 retval = tty_check_change(tty);
901 if (retval)
902 return retval;
903 switch (arg) {
904 case TCOOFF:
905 if (!tty->flow_stopped) {
906 tty->flow_stopped = 1;
907 stop_tty(tty);
908 }
909 break;
910 case TCOON:
911 if (tty->flow_stopped) {
912 tty->flow_stopped = 0;
913 start_tty(tty);
914 }
915 break;
916 case TCIOFF:
917 if (STOP_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700918 return send_prio_char(tty, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 break;
920 case TCION:
921 if (START_CHAR(tty) != __DISABLED_CHAR)
Alan Cox5f412b22006-09-29 02:01:40 -0700922 return send_prio_char(tty, START_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 break;
924 default:
925 return -EINVAL;
926 }
927 return 0;
928 case TCFLSH:
Alan Cox0fc00e22007-11-07 01:24:56 -0800929 return tty_perform_flush(tty, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 case TIOCOUTQ:
931 return put_user(tty->driver->chars_in_buffer ?
932 tty->driver->chars_in_buffer(tty) : 0,
933 (int __user *) arg);
934 case TIOCINQ:
935 retval = tty->read_cnt;
936 if (L_ICANON(tty))
937 retval = inq_canon(tty);
938 return put_user(retval, (unsigned int __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 case TIOCPKT:
940 {
941 int pktmode;
942
943 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
944 tty->driver->subtype != PTY_TYPE_MASTER)
945 return -ENOTTY;
946 if (get_user(pktmode, (int __user *) arg))
947 return -EFAULT;
948 if (pktmode) {
949 if (!tty->packet) {
950 tty->packet = 1;
951 tty->link->ctrl_status = 0;
952 }
953 } else
954 tty->packet = 0;
955 return 0;
956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 default:
Alan Cox0fc00e22007-11-07 01:24:56 -0800958 /* Try the mode commands */
959 return tty_mode_ioctl(tty, file, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 }
961}
962
963EXPORT_SYMBOL(n_tty_ioctl);