blob: f95a80b2265fdf0f42829f750c0c19f491eec044 [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
Alan Cox355d95a12008-02-08 04:18:48 -080053void tty_wait_until_sent(struct tty_struct *tty, long timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054{
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
56 char buf[64];
Alan Cox355d95a12008-02-08 04:18:48 -080057
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 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,
Cory T. Tusardb992472007-12-23 12:34:51 -080065 !tty->driver->chars_in_buffer(tty), timeout) < 0)
Jiri Slaby5a52bd42007-07-15 23:40:18 -070066 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}
Linus Torvalds1da177e2005-04-16 15:20:36 -070070EXPORT_SYMBOL(tty_wait_until_sent);
71
Alan Coxedc6afc2006-12-08 02:38:44 -080072static void unset_locked_termios(struct ktermios *termios,
73 struct ktermios *old,
74 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
76 int i;
Alan Cox355d95a12008-02-08 04:18:48 -080077
78#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80 if (!locked) {
81 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
82 return;
83 }
84
85 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
86 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
87 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
88 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
89 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
Alan Cox355d95a12008-02-08 04:18:48 -080090 for (i = 0; i < NCCS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 termios->c_cc[i] = locked->c_cc[i] ?
92 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -080093 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
Alan Coxedc6afc2006-12-08 02:38:44 -080096/*
97 * Routine which returns the baud rate of the tty
98 *
99 * Note that the baud_table needs to be kept in sync with the
100 * include/asm/termbits.h file.
101 */
102static const speed_t baud_table[] = {
103 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
104 9600, 19200, 38400, 57600, 115200, 230400, 460800,
105#ifdef __sparc__
106 76800, 153600, 307200, 614400, 921600
107#else
108 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
109 2500000, 3000000, 3500000, 4000000
110#endif
111};
112
113#ifndef __sparc__
114static const tcflag_t baud_bits[] = {
115 B0, B50, B75, B110, B134, B150, B200, B300, B600,
116 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
117 B57600, B115200, B230400, B460800, B500000, B576000,
118 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
119 B3000000, B3500000, B4000000
120};
121#else
122static const tcflag_t baud_bits[] = {
123 B0, B50, B75, B110, B134, B150, B200, B300, B600,
124 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
125 B57600, B115200, B230400, B460800, B76800, B153600,
126 B307200, B614400, B921600
127};
128#endif
129
130static int n_baud_table = ARRAY_SIZE(baud_table);
131
132/**
133 * tty_termios_baud_rate
134 * @termios: termios structure
135 *
136 * Convert termios baud rate data into a speed. This should be called
137 * with the termios lock held if this termios is a terminal termios
138 * structure. May change the termios data. Device drivers can call this
139 * function but should use ->c_[io]speed directly as they are updated.
140 *
141 * Locking: none
142 */
143
144speed_t tty_termios_baud_rate(struct ktermios *termios)
145{
146 unsigned int cbaud;
147
148 cbaud = termios->c_cflag & CBAUD;
149
150#ifdef BOTHER
151 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
152 if (cbaud == BOTHER)
153 return termios->c_ospeed;
154#endif
155 if (cbaud & CBAUDEX) {
156 cbaud &= ~CBAUDEX;
157
158 if (cbaud < 1 || cbaud + 15 > n_baud_table)
159 termios->c_cflag &= ~CBAUDEX;
160 else
161 cbaud += 15;
162 }
163 return baud_table[cbaud];
164}
Alan Coxedc6afc2006-12-08 02:38:44 -0800165EXPORT_SYMBOL(tty_termios_baud_rate);
166
167/**
168 * tty_termios_input_baud_rate
169 * @termios: termios structure
170 *
171 * Convert termios baud rate data into a speed. This should be called
172 * with the termios lock held if this termios is a terminal termios
173 * structure. May change the termios data. Device drivers can call this
174 * function but should use ->c_[io]speed directly as they are updated.
175 *
176 * Locking: none
177 */
178
179speed_t tty_termios_input_baud_rate(struct ktermios *termios)
180{
181#ifdef IBSHIFT
182 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
183
184 if (cbaud == B0)
185 return tty_termios_baud_rate(termios);
186
187 /* Magic token for arbitary speed via c_ispeed*/
188 if (cbaud == BOTHER)
189 return termios->c_ispeed;
190
191 if (cbaud & CBAUDEX) {
192 cbaud &= ~CBAUDEX;
193
194 if (cbaud < 1 || cbaud + 15 > n_baud_table)
195 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
196 else
197 cbaud += 15;
198 }
199 return baud_table[cbaud];
200#else
201 return tty_termios_baud_rate(termios);
202#endif
203}
Alan Coxedc6afc2006-12-08 02:38:44 -0800204EXPORT_SYMBOL(tty_termios_input_baud_rate);
205
Alan Coxedc6afc2006-12-08 02:38:44 -0800206/**
207 * tty_termios_encode_baud_rate
Alan Cox78137e32007-02-10 01:45:57 -0800208 * @termios: ktermios structure holding user requested state
Alan Coxedc6afc2006-12-08 02:38:44 -0800209 * @ispeed: input speed
210 * @ospeed: output speed
211 *
212 * Encode the speeds set into the passed termios structure. This is
213 * used as a library helper for drivers os that they can report back
214 * the actual speed selected when it differs from the speed requested
215 *
Alan Cox78137e32007-02-10 01:45:57 -0800216 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
217 * we need to carefully set the bits when the user does not get the
218 * desired speed. We allow small margins and preserve as much of possible
219 * of the input intent to keep compatiblity.
Alan Coxedc6afc2006-12-08 02:38:44 -0800220 *
221 * Locking: Caller should hold termios lock. This is already held
222 * when calling this function from the driver termios handler.
Alan Cox5f519d72007-10-16 23:30:07 -0700223 *
224 * The ifdefs deal with platforms whose owners have yet to update them
225 * and will all go away once this is done.
Alan Coxedc6afc2006-12-08 02:38:44 -0800226 */
227
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700228void tty_termios_encode_baud_rate(struct ktermios *termios,
229 speed_t ibaud, speed_t obaud)
Alan Coxedc6afc2006-12-08 02:38:44 -0800230{
231 int i = 0;
Alan Cox78137e32007-02-10 01:45:57 -0800232 int ifound = -1, ofound = -1;
233 int iclose = ibaud/50, oclose = obaud/50;
234 int ibinput = 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800235
Alan Cox5f519d72007-10-16 23:30:07 -0700236 if (obaud == 0) /* CD dropped */
237 ibaud = 0; /* Clear ibaud to be sure */
238
Alan Coxedc6afc2006-12-08 02:38:44 -0800239 termios->c_ispeed = ibaud;
240 termios->c_ospeed = obaud;
241
Alan Cox5f519d72007-10-16 23:30:07 -0700242#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800243 /* If the user asked for a precise weird speed give a precise weird
244 answer. If they asked for a Bfoo speed they many have problems
245 digesting non-exact replies so fuzz a bit */
246
247 if ((termios->c_cflag & CBAUD) == BOTHER)
248 oclose = 0;
249 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
250 iclose = 0;
251 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
252 ibinput = 1; /* An input speed was specified */
Alan Cox5f519d72007-10-16 23:30:07 -0700253#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800254 termios->c_cflag &= ~CBAUD;
Alan Coxedc6afc2006-12-08 02:38:44 -0800255
Alan Cox5f519d72007-10-16 23:30:07 -0700256 /*
257 * Our goal is to find a close match to the standard baud rate
258 * returned. Walk the baud rate table and if we get a very close
259 * match then report back the speed as a POSIX Bxxxx value by
260 * preference
261 */
262
Alan Coxedc6afc2006-12-08 02:38:44 -0800263 do {
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700264 if (obaud - oclose <= baud_table[i] &&
265 obaud + oclose >= baud_table[i]) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800266 termios->c_cflag |= baud_bits[i];
Alan Cox78137e32007-02-10 01:45:57 -0800267 ofound = i;
Alan Coxedc6afc2006-12-08 02:38:44 -0800268 }
Maciej W. Rozycki75e8b712007-10-18 03:04:35 -0700269 if (ibaud - iclose <= baud_table[i] &&
270 ibaud + iclose >= baud_table[i]) {
271 /* For the case input == output don't set IBAUD bits
272 if the user didn't do so */
Alan Cox5f519d72007-10-16 23:30:07 -0700273 if (ofound == i && !ibinput)
274 ifound = i;
275#ifdef IBSHIFT
276 else {
277 ifound = i;
Alan Cox78137e32007-02-10 01:45:57 -0800278 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700279 }
280#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800281 }
Jiri Slaby68043962007-07-15 23:40:18 -0700282 } while (++i < n_baud_table);
Alan Cox5f519d72007-10-16 23:30:07 -0700283
284 /*
285 * If we found no match then use BOTHER if provided or warn
286 * the user their platform maintainer needs to wake up if not.
287 */
288#ifdef BOTHER
Alan Cox78137e32007-02-10 01:45:57 -0800289 if (ofound == -1)
Alan Coxedc6afc2006-12-08 02:38:44 -0800290 termios->c_cflag |= BOTHER;
Alan Cox78137e32007-02-10 01:45:57 -0800291 /* Set exact input bits only if the input and output differ or the
292 user already did */
Jiri Slaby68043962007-07-15 23:40:18 -0700293 if (ifound == -1 && (ibaud != obaud || ibinput))
Alan Coxedc6afc2006-12-08 02:38:44 -0800294 termios->c_cflag |= (BOTHER << IBSHIFT);
Alan Cox5f519d72007-10-16 23:30:07 -0700295#else
296 if (ifound == -1 || ofound == -1) {
297 static int warned;
298 if (!warned++)
299 printk(KERN_WARNING "tty: Unable to return correct "
300 "speed data as your architecture needs updating.\n");
301 }
302#endif
Alan Coxedc6afc2006-12-08 02:38:44 -0800303}
Alan Coxedc6afc2006-12-08 02:38:44 -0800304EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
305
Alan Cox5f519d72007-10-16 23:30:07 -0700306void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
307{
308 tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
309}
310EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
Alan Coxedc6afc2006-12-08 02:38:44 -0800311
312/**
313 * tty_get_baud_rate - get tty bit rates
314 * @tty: tty to query
315 *
316 * Returns the baud rate as an integer for this terminal. The
317 * termios lock must be held by the caller and the terminal bit
318 * flags may be updated.
319 *
320 * Locking: none
321 */
322
323speed_t tty_get_baud_rate(struct tty_struct *tty)
324{
325 speed_t baud = tty_termios_baud_rate(tty->termios);
326
327 if (baud == 38400 && tty->alt_speed) {
328 if (!tty->warned) {
329 printk(KERN_WARNING "Use of setserial/setrocket to "
330 "set SPD_* flags is deprecated\n");
331 tty->warned = 1;
332 }
333 baud = tty->alt_speed;
334 }
335
336 return baud;
337}
Alan Coxedc6afc2006-12-08 02:38:44 -0800338EXPORT_SYMBOL(tty_get_baud_rate);
339
Alan Coxaf9b8972006-08-27 01:24:01 -0700340/**
Alan Cox5f519d72007-10-16 23:30:07 -0700341 * tty_termios_copy_hw - copy hardware settings
342 * @new: New termios
343 * @old: Old termios
344 *
345 * Propogate the hardware specific terminal setting bits from
346 * the old termios structure to the new one. This is used in cases
347 * where the hardware does not support reconfiguration or as a helper
348 * in some cases where only minimal reconfiguration is supported
349 */
350
351void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
352{
353 /* The bits a dumb device handles in software. Smart devices need
354 to always provide a set_termios method */
355 new->c_cflag &= HUPCL | CREAD | CLOCAL;
356 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
357 new->c_ispeed = old->c_ispeed;
358 new->c_ospeed = old->c_ospeed;
359}
Alan Cox5f519d72007-10-16 23:30:07 -0700360EXPORT_SYMBOL(tty_termios_copy_hw);
361
362/**
Alan Coxbf5e5832008-01-08 14:55:51 +0000363 * tty_termios_hw_change - check for setting change
364 * @a: termios
365 * @b: termios to compare
366 *
367 * Check if any of the bits that affect a dumb device have changed
368 * between the two termios structures, or a speed change is needed.
369 */
370
371int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
372{
373 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
374 return 1;
375 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
376 return 1;
377 return 0;
378}
379EXPORT_SYMBOL(tty_termios_hw_change);
380
381/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700382 * change_termios - update termios values
383 * @tty: tty to update
384 * @new_termios: desired new value
385 *
386 * Perform updates to the termios values set on this terminal. There
387 * is a bit of layering violation here with n_tty in terms of the
388 * internal knowledge of this function.
389 *
390 * Locking: termios_sem
391 */
392
Alan Cox355d95a12008-02-08 04:18:48 -0800393static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
395 int canon_change;
Alan Coxedc6afc2006-12-08 02:38:44 -0800396 struct ktermios old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 struct tty_ldisc *ld;
Alan Cox355d95a12008-02-08 04:18:48 -0800398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 /*
400 * Perform the actual termios internal changes under lock.
401 */
Alan Cox355d95a12008-02-08 04:18:48 -0800402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 /* FIXME: we need to decide on some locking/ordering semantics
405 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700406 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408 *tty->termios = *new_termios;
409 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
410 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
411 if (canon_change) {
412 memset(&tty->read_flags, 0, sizeof tty->read_flags);
413 tty->canon_head = tty->read_tail;
414 tty->canon_data = 0;
415 tty->erasing = 0;
416 }
Alan Cox355d95a12008-02-08 04:18:48 -0800417
Alan Cox5f519d72007-10-16 23:30:07 -0700418 /* This bit should be in the ldisc code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
420 /* Get characters left over from canonical mode. */
421 wake_up_interruptible(&tty->read_wait);
422
423 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 if (tty->link && tty->link->packet) {
425 int old_flow = ((old_termios.c_iflag & IXON) &&
426 (old_termios.c_cc[VSTOP] == '\023') &&
427 (old_termios.c_cc[VSTART] == '\021'));
428 int new_flow = (I_IXON(tty) &&
429 STOP_CHAR(tty) == '\023' &&
430 START_CHAR(tty) == '\021');
431 if (old_flow != new_flow) {
432 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
433 if (new_flow)
434 tty->ctrl_status |= TIOCPKT_DOSTOP;
435 else
436 tty->ctrl_status |= TIOCPKT_NOSTOP;
437 wake_up_interruptible(&tty->link->read_wait);
438 }
439 }
Alan Cox355d95a12008-02-08 04:18:48 -0800440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 if (tty->driver->set_termios)
442 (*tty->driver->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700443 else
444 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 ld = tty_ldisc_ref(tty);
447 if (ld != NULL) {
448 if (ld->set_termios)
449 (ld->set_termios)(tty, &old_termios);
450 tty_ldisc_deref(ld);
451 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700452 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
Alan Coxaf9b8972006-08-27 01:24:01 -0700455/**
456 * set_termios - set termios values for a tty
457 * @tty: terminal device
458 * @arg: user data
459 * @opt: option information
460 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200461 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700462 * functions before using change_termios to do the actual changes.
463 *
464 * Locking:
465 * Called functions take ldisc and termios_sem locks
466 */
467
Alan Cox355d95a12008-02-08 04:18:48 -0800468static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
Alan Coxedc6afc2006-12-08 02:38:44 -0800470 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 struct tty_ldisc *ld;
472 int retval = tty_check_change(tty);
473
474 if (retval)
475 return retval;
476
Alan Cox64bb6c52006-12-08 02:38:47 -0800477 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 if (user_termio_to_kernel_termios(&tmp_termios,
481 (struct termio __user *)arg))
482 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800483#ifdef TCGETS2
484 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800485 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 (struct termios __user *)arg))
487 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800488 } else {
489 if (user_termios_to_kernel_termios(&tmp_termios,
490 (struct termios2 __user *)arg))
491 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800493#else
494 } else if (user_termios_to_kernel_termios(&tmp_termios,
495 (struct termios __user *)arg))
496 return -EFAULT;
497#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Alan Cox355d95a12008-02-08 04:18:48 -0800499 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
500 * with the real speed so its unconditionally usable */
Alan Coxedc6afc2006-12-08 02:38:44 -0800501 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
502 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 ld = tty_ldisc_ref(tty);
Alan Cox355d95a12008-02-08 04:18:48 -0800505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (ld != NULL) {
507 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
508 ld->flush_buffer(tty);
509 tty_ldisc_deref(ld);
510 }
Alan Cox355d95a12008-02-08 04:18:48 -0800511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (opt & TERMIOS_WAIT) {
513 tty_wait_until_sent(tty, 0);
514 if (signal_pending(current))
515 return -EINTR;
516 }
517
518 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700519
520 /* FIXME: Arguably if tmp_termios == tty->termios AND the
521 actual requested termios was not tmp_termios then we may
522 want to return an error as no user requested change has
523 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return 0;
525}
526
Alan Cox355d95a12008-02-08 04:18:48 -0800527static int get_termio(struct tty_struct *tty, struct termio __user *termio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 if (kernel_termios_to_user_termio(termio, tty->termios))
530 return -EFAULT;
531 return 0;
532}
533
Alan Cox355d95a12008-02-08 04:18:48 -0800534static unsigned long inq_canon(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
536 int nr, head, tail;
537
538 if (!tty->canon_data || !tty->read_buf)
539 return 0;
540 head = tty->canon_head;
541 tail = tty->read_tail;
542 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
543 /* Skip EOF-chars.. */
544 while (head != tail) {
545 if (test_bit(tail, tty->read_flags) &&
546 tty->read_buf[tail] == __DISABLED_CHAR)
547 nr--;
548 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
549 }
550 return nr;
551}
552
553#ifdef TIOCGETP
554/*
555 * These are deprecated, but there is limited support..
556 *
557 * The "sg_flags" translation is a joke..
558 */
Alan Cox355d95a12008-02-08 04:18:48 -0800559static int get_sgflags(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 int flags = 0;
562
563 if (!(tty->termios->c_lflag & ICANON)) {
564 if (tty->termios->c_lflag & ISIG)
565 flags |= 0x02; /* cbreak */
566 else
567 flags |= 0x20; /* raw */
568 }
569 if (tty->termios->c_lflag & ECHO)
570 flags |= 0x08; /* echo */
571 if (tty->termios->c_oflag & OPOST)
572 if (tty->termios->c_oflag & ONLCR)
573 flags |= 0x10; /* crmod */
574 return flags;
575}
576
Alan Cox355d95a12008-02-08 04:18:48 -0800577static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
579 struct sgttyb tmp;
580
Arjan van de Ven5785c952006-09-29 02:00:43 -0700581 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800582 tmp.sg_ispeed = tty->termios->c_ispeed;
583 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 tmp.sg_erase = tty->termios->c_cc[VERASE];
585 tmp.sg_kill = tty->termios->c_cc[VKILL];
586 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700587 mutex_unlock(&tty->termios_mutex);
Alan Cox355d95a12008-02-08 04:18:48 -0800588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
590}
591
Alan Cox355d95a12008-02-08 04:18:48 -0800592static void set_sgflags(struct ktermios *termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 termios->c_iflag = ICRNL | IXON;
595 termios->c_oflag = 0;
596 termios->c_lflag = ISIG | ICANON;
597 if (flags & 0x02) { /* cbreak */
598 termios->c_iflag = 0;
599 termios->c_lflag &= ~ICANON;
600 }
601 if (flags & 0x08) { /* echo */
602 termios->c_lflag |= ECHO | ECHOE | ECHOK |
603 ECHOCTL | ECHOKE | IEXTEN;
604 }
605 if (flags & 0x10) { /* crmod */
606 termios->c_oflag |= OPOST | ONLCR;
607 }
608 if (flags & 0x20) { /* raw */
609 termios->c_iflag = 0;
610 termios->c_lflag &= ~(ISIG | ICANON);
611 }
612 if (!(termios->c_lflag & ICANON)) {
613 termios->c_cc[VMIN] = 1;
614 termios->c_cc[VTIME] = 0;
615 }
616}
617
Alan Coxaf9b8972006-08-27 01:24:01 -0700618/**
619 * set_sgttyb - set legacy terminal values
620 * @tty: tty structure
621 * @sgttyb: pointer to old style terminal structure
622 *
623 * Updates a terminal from the legacy BSD style terminal information
624 * structure.
625 *
626 * Locking: termios_sem
627 */
628
Alan Cox355d95a12008-02-08 04:18:48 -0800629static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
631 int retval;
632 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800633 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 retval = tty_check_change(tty);
636 if (retval)
637 return retval;
Alan Cox355d95a12008-02-08 04:18:48 -0800638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
640 return -EFAULT;
641
Arjan van de Ven5785c952006-09-29 02:00:43 -0700642 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700643 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 termios.c_cc[VERASE] = tmp.sg_erase;
645 termios.c_cc[VKILL] = tmp.sg_kill;
646 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800647 /* Try and encode into Bfoo format */
648#ifdef BOTHER
Alan Cox355d95a12008-02-08 04:18:48 -0800649 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
650 termios.c_ospeed);
Alan Coxedc6afc2006-12-08 02:38:44 -0800651#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700652 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 change_termios(tty, &termios);
654 return 0;
655}
656#endif
657
658#ifdef TIOCGETC
Alan Cox355d95a12008-02-08 04:18:48 -0800659static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
661 struct tchars tmp;
662
663 tmp.t_intrc = tty->termios->c_cc[VINTR];
664 tmp.t_quitc = tty->termios->c_cc[VQUIT];
665 tmp.t_startc = tty->termios->c_cc[VSTART];
666 tmp.t_stopc = tty->termios->c_cc[VSTOP];
667 tmp.t_eofc = tty->termios->c_cc[VEOF];
668 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
669 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
670}
671
Alan Cox355d95a12008-02-08 04:18:48 -0800672static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 struct tchars tmp;
675
676 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
677 return -EFAULT;
678 tty->termios->c_cc[VINTR] = tmp.t_intrc;
679 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
680 tty->termios->c_cc[VSTART] = tmp.t_startc;
681 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
682 tty->termios->c_cc[VEOF] = tmp.t_eofc;
683 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
684 return 0;
685}
686#endif
687
688#ifdef TIOCGLTC
Alan Cox355d95a12008-02-08 04:18:48 -0800689static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 struct ltchars tmp;
692
693 tmp.t_suspc = tty->termios->c_cc[VSUSP];
Alan Cox355d95a12008-02-08 04:18:48 -0800694 /* what is dsuspc anyway? */
695 tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
Alan Cox355d95a12008-02-08 04:18:48 -0800697 /* what is flushc anyway? */
698 tmp.t_flushc = tty->termios->c_cc[VEOL2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 tmp.t_werasc = tty->termios->c_cc[VWERASE];
700 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
701 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
702}
703
Alan Cox355d95a12008-02-08 04:18:48 -0800704static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 struct ltchars tmp;
707
708 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
709 return -EFAULT;
710
711 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
Alan Cox355d95a12008-02-08 04:18:48 -0800712 /* what is dsuspc anyway? */
713 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
Alan Cox355d95a12008-02-08 04:18:48 -0800715 /* what is flushc anyway? */
716 tty->termios->c_cc[VEOL2] = tmp.t_flushc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
718 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
719 return 0;
720}
721#endif
722
Alan Coxaf9b8972006-08-27 01:24:01 -0700723/**
724 * send_prio_char - send priority character
725 *
726 * Send a high priority character to the tty even if stopped
727 *
Alan Cox5f412b22006-09-29 02:01:40 -0700728 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700730
Alan Cox5f412b22006-09-29 02:01:40 -0700731static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
733 int was_stopped = tty->stopped;
734
735 if (tty->driver->send_xchar) {
736 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700737 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
Alan Cox5f412b22006-09-29 02:01:40 -0700739
Alan Cox9c1729d2007-07-15 23:39:43 -0700740 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700741 return -ERESTARTSYS;
742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (was_stopped)
744 start_tty(tty);
745 tty->driver->write(tty, &ch, 1);
746 if (was_stopped)
747 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700748 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700749 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
Alan Cox0fc00e22007-11-07 01:24:56 -0800752/**
753 * tty_mode_ioctl - mode related ioctls
754 * @tty: tty for the ioctl
755 * @file: file pointer for the tty
756 * @cmd: command
757 * @arg: ioctl argument
758 *
759 * Perform non line discipline specific mode control ioctls. This
760 * is designed to be called by line disciplines to ensure they provide
761 * consistent mode setting.
762 */
763
Alan Cox355d95a12008-02-08 04:18:48 -0800764int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800765 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Alan Cox355d95a12008-02-08 04:18:48 -0800767 struct tty_struct *real_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 void __user *p = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
771 tty->driver->subtype == PTY_TYPE_MASTER)
772 real_tty = tty->link;
773 else
774 real_tty = tty;
775
776 switch (cmd) {
777#ifdef TIOCGETP
Alan Cox355d95a12008-02-08 04:18:48 -0800778 case TIOCGETP:
779 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
780 case TIOCSETP:
781 case TIOCSETN:
782 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783#endif
784#ifdef TIOCGETC
Alan Cox355d95a12008-02-08 04:18:48 -0800785 case TIOCGETC:
786 return get_tchars(real_tty, p);
787 case TIOCSETC:
788 return set_tchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789#endif
790#ifdef TIOCGLTC
Alan Cox355d95a12008-02-08 04:18:48 -0800791 case TIOCGLTC:
792 return get_ltchars(real_tty, p);
793 case TIOCSLTC:
794 return set_ltchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795#endif
Alan Cox355d95a12008-02-08 04:18:48 -0800796 case TCSETSF:
797 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
798 case TCSETSW:
799 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
800 case TCSETS:
801 return set_termios(real_tty, p, TERMIOS_OLD);
Alan Coxedc6afc2006-12-08 02:38:44 -0800802#ifndef TCGETS2
Alan Cox355d95a12008-02-08 04:18:48 -0800803 case TCGETS:
804 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
805 return -EFAULT;
806 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800807#else
Alan Cox355d95a12008-02-08 04:18:48 -0800808 case TCGETS:
809 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
810 return -EFAULT;
811 return 0;
812 case TCGETS2:
813 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
814 return -EFAULT;
815 return 0;
816 case TCSETSF2:
817 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
818 case TCSETSW2:
819 return set_termios(real_tty, p, TERMIOS_WAIT);
820 case TCSETS2:
821 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800822#endif
Alan Cox355d95a12008-02-08 04:18:48 -0800823 case TCGETA:
824 return get_termio(real_tty, p);
825 case TCSETAF:
826 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
827 case TCSETAW:
828 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
829 case TCSETA:
830 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -0800831#ifndef TCGETS2
Alan Cox355d95a12008-02-08 04:18:48 -0800832 case TIOCGLCKTRMIOS:
833 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
834 return -EFAULT;
835 return 0;
836 case TIOCSLCKTRMIOS:
837 if (!capable(CAP_SYS_ADMIN))
838 return -EPERM;
839 if (user_termios_to_kernel_termios(real_tty->termios_locked,
840 (struct termios __user *) arg))
841 return -EFAULT;
842 return 0;
Alan Cox0fc00e22007-11-07 01:24:56 -0800843#else
Alan Cox355d95a12008-02-08 04:18:48 -0800844 case TIOCGLCKTRMIOS:
845 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
846 return -EFAULT;
847 return 0;
848 case TIOCSLCKTRMIOS:
849 if (!capable(CAP_SYS_ADMIN))
850 return -EPERM;
851 if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
852 (struct termios __user *) arg))
853 return -EFAULT;
Alan Cox0fc00e22007-11-07 01:24:56 -0800854 return 0;
855#endif
Alan Cox355d95a12008-02-08 04:18:48 -0800856 case TIOCGSOFTCAR:
857 return put_user(C_CLOCAL(tty) ? 1 : 0,
858 (int __user *)arg);
859 case TIOCSSOFTCAR:
860 if (get_user(arg, (unsigned int __user *) arg))
861 return -EFAULT;
862 mutex_lock(&tty->termios_mutex);
863 tty->termios->c_cflag =
864 ((tty->termios->c_cflag & ~CLOCAL) |
865 (arg ? CLOCAL : 0));
866 mutex_unlock(&tty->termios_mutex);
867 return 0;
868 default:
869 return -ENOIOCTLCMD;
Alan Cox0fc00e22007-11-07 01:24:56 -0800870 }
871}
Alan Cox0fc00e22007-11-07 01:24:56 -0800872EXPORT_SYMBOL_GPL(tty_mode_ioctl);
873
874int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
875{
876 struct tty_ldisc *ld;
877 int retval = tty_check_change(tty);
878 if (retval)
879 return retval;
880
881 ld = tty_ldisc_ref(tty);
882 switch (arg) {
883 case TCIFLUSH:
884 if (ld && ld->flush_buffer)
885 ld->flush_buffer(tty);
886 break;
887 case TCIOFLUSH:
888 if (ld && ld->flush_buffer)
889 ld->flush_buffer(tty);
890 /* fall through */
891 case TCOFLUSH:
892 if (tty->driver->flush_buffer)
893 tty->driver->flush_buffer(tty);
894 break;
895 default:
896 tty_ldisc_deref(ld);
897 return -EINVAL;
898 }
899 tty_ldisc_deref(ld);
900 return 0;
901}
Alan Cox0fc00e22007-11-07 01:24:56 -0800902EXPORT_SYMBOL_GPL(tty_perform_flush);
903
Alan Cox355d95a12008-02-08 04:18:48 -0800904int n_tty_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800905 unsigned int cmd, unsigned long arg)
906{
Alan Cox355d95a12008-02-08 04:18:48 -0800907 struct tty_struct *real_tty;
Alan Cox0fc00e22007-11-07 01:24:56 -0800908 int retval;
909
910 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
911 tty->driver->subtype == PTY_TYPE_MASTER)
912 real_tty = tty->link;
913 else
914 real_tty = tty;
915
916 switch (cmd) {
Alan Cox355d95a12008-02-08 04:18:48 -0800917 case TCXONC:
918 retval = tty_check_change(tty);
919 if (retval)
920 return retval;
921 switch (arg) {
922 case TCOOFF:
923 if (!tty->flow_stopped) {
924 tty->flow_stopped = 1;
925 stop_tty(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 }
Alan Cox355d95a12008-02-08 04:18:48 -0800927 break;
928 case TCOON:
929 if (tty->flow_stopped) {
930 tty->flow_stopped = 0;
931 start_tty(tty);
932 }
933 break;
934 case TCIOFF:
935 if (STOP_CHAR(tty) != __DISABLED_CHAR)
936 return send_prio_char(tty, STOP_CHAR(tty));
937 break;
938 case TCION:
939 if (START_CHAR(tty) != __DISABLED_CHAR)
940 return send_prio_char(tty, START_CHAR(tty));
941 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 default:
Alan Cox355d95a12008-02-08 04:18:48 -0800943 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
Alan Cox355d95a12008-02-08 04:18:48 -0800945 return 0;
946 case TCFLSH:
947 return tty_perform_flush(tty, arg);
948 case TIOCOUTQ:
949 return put_user(tty->driver->chars_in_buffer ?
950 tty->driver->chars_in_buffer(tty) : 0,
951 (int __user *) arg);
952 case TIOCINQ:
953 retval = tty->read_cnt;
954 if (L_ICANON(tty))
955 retval = inq_canon(tty);
956 return put_user(retval, (unsigned int __user *) arg);
957 case TIOCPKT:
958 {
959 int pktmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Alan Cox355d95a12008-02-08 04:18:48 -0800961 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
962 tty->driver->subtype != PTY_TYPE_MASTER)
963 return -ENOTTY;
964 if (get_user(pktmode, (int __user *) arg))
965 return -EFAULT;
966 if (pktmode) {
967 if (!tty->packet) {
968 tty->packet = 1;
969 tty->link->ctrl_status = 0;
970 }
971 } else
972 tty->packet = 0;
973 return 0;
974 }
975 default:
976 /* Try the mode commands */
977 return tty_mode_ioctl(tty, file, cmd, arg);
978 }
979}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980EXPORT_SYMBOL(n_tty_ioctl);