blob: 8c4bf3e48d5b163533360f4cbf442dcd8322d714 [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>
Alan Cox0ee9cbb2008-04-30 00:53:32 -070024#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include <asm/io.h>
27#include <asm/uaccess.h>
28#include <asm/system.h>
29
30#undef TTY_DEBUG_WAIT_UNTIL_SENT
31
32#undef DEBUG
33
34/*
35 * Internal flag options for termios setting behavior
36 */
37#define TERMIOS_FLUSH 1
38#define TERMIOS_WAIT 2
39#define TERMIOS_TERMIO 4
Alan Coxedc6afc2006-12-08 02:38:44 -080040#define TERMIOS_OLD 8
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Alan Coxaf9b8972006-08-27 01:24:01 -070042
43/**
44 * tty_wait_until_sent - wait for I/O to finish
45 * @tty: tty we are waiting for
46 * @timeout: how long we will wait
47 *
48 * Wait for characters pending in a tty driver to hit the wire, or
49 * for a timeout to occur (eg due to flow control)
50 *
51 * Locking: none
52 */
53
Alan Cox355d95a2008-02-08 04:18:48 -080054void tty_wait_until_sent(struct tty_struct *tty, long timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -070055{
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
57 char buf[64];
Alan Cox355d95a2008-02-08 04:18:48 -080058
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
60#endif
61 if (!tty->driver->chars_in_buffer)
62 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 if (!timeout)
64 timeout = MAX_SCHEDULE_TIMEOUT;
Alan Cox0ee9cbb2008-04-30 00:53:32 -070065 lock_kernel();
Jiri Slaby5a52bd42007-07-15 23:40:18 -070066 if (wait_event_interruptible_timeout(tty->write_wait,
Alan Cox0ee9cbb2008-04-30 00:53:32 -070067 !tty->driver->chars_in_buffer(tty), timeout) >= 0) {
68 if (tty->driver->wait_until_sent)
69 tty->driver->wait_until_sent(tty, timeout);
70 }
71 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
Linus Torvalds1da177e2005-04-16 15:20:36 -070073EXPORT_SYMBOL(tty_wait_until_sent);
74
Alan Coxedc6afc2006-12-08 02:38:44 -080075static void unset_locked_termios(struct ktermios *termios,
76 struct ktermios *old,
77 struct ktermios *locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 int i;
Alan Cox355d95a2008-02-08 04:18:48 -080080
81#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83 if (!locked) {
84 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
85 return;
86 }
87
88 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
89 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
90 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
91 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
92 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
Alan Cox355d95a2008-02-08 04:18:48 -080093 for (i = 0; i < NCCS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 termios->c_cc[i] = locked->c_cc[i] ?
95 old->c_cc[i] : termios->c_cc[i];
Alan Coxedc6afc2006-12-08 02:38:44 -080096 /* FIXME: What should we do for i/ospeed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
Alan Coxedc6afc2006-12-08 02:38:44 -080099/*
100 * Routine which returns the baud rate of the tty
101 *
102 * Note that the baud_table needs to be kept in sync with the
103 * include/asm/termbits.h file.
104 */
105static const speed_t baud_table[] = {
106 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
107 9600, 19200, 38400, 57600, 115200, 230400, 460800,
108#ifdef __sparc__
109 76800, 153600, 307200, 614400, 921600
110#else
111 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
112 2500000, 3000000, 3500000, 4000000
113#endif
114};
115
116#ifndef __sparc__
117static const tcflag_t baud_bits[] = {
118 B0, B50, B75, B110, B134, B150, B200, B300, B600,
119 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
120 B57600, B115200, B230400, B460800, B500000, B576000,
121 B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
122 B3000000, B3500000, B4000000
123};
124#else
125static const tcflag_t baud_bits[] = {
126 B0, B50, B75, B110, B134, B150, B200, B300, B600,
127 B1200, B1800, B2400, B4800, B9600, B19200, B38400,
128 B57600, B115200, B230400, B460800, B76800, B153600,
129 B307200, B614400, B921600
130};
131#endif
132
133static int n_baud_table = ARRAY_SIZE(baud_table);
134
135/**
136 * tty_termios_baud_rate
137 * @termios: termios structure
138 *
139 * Convert termios baud rate data into a speed. This should be called
140 * with the termios lock held if this termios is a terminal termios
141 * structure. May change the termios data. Device drivers can call this
142 * function but should use ->c_[io]speed directly as they are updated.
143 *
144 * Locking: none
145 */
146
147speed_t tty_termios_baud_rate(struct ktermios *termios)
148{
149 unsigned int cbaud;
150
151 cbaud = termios->c_cflag & CBAUD;
152
153#ifdef BOTHER
154 /* Magic token for arbitary speed via c_ispeed/c_ospeed */
155 if (cbaud == BOTHER)
156 return termios->c_ospeed;
157#endif
158 if (cbaud & CBAUDEX) {
159 cbaud &= ~CBAUDEX;
160
161 if (cbaud < 1 || cbaud + 15 > n_baud_table)
162 termios->c_cflag &= ~CBAUDEX;
163 else
164 cbaud += 15;
165 }
166 return baud_table[cbaud];
167}
Alan Coxedc6afc2006-12-08 02:38:44 -0800168EXPORT_SYMBOL(tty_termios_baud_rate);
169
170/**
171 * tty_termios_input_baud_rate
172 * @termios: termios structure
173 *
174 * Convert termios baud rate data into a speed. This should be called
175 * with the termios lock held if this termios is a terminal termios
176 * structure. May change the termios data. Device drivers can call this
177 * function but should use ->c_[io]speed directly as they are updated.
178 *
179 * Locking: none
180 */
181
182speed_t tty_termios_input_baud_rate(struct ktermios *termios)
183{
184#ifdef IBSHIFT
185 unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
186
187 if (cbaud == B0)
188 return tty_termios_baud_rate(termios);
189
190 /* Magic token for arbitary speed via c_ispeed*/
191 if (cbaud == BOTHER)
192 return termios->c_ispeed;
193
194 if (cbaud & CBAUDEX) {
195 cbaud &= ~CBAUDEX;
196
197 if (cbaud < 1 || cbaud + 15 > n_baud_table)
198 termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
199 else
200 cbaud += 15;
201 }
202 return baud_table[cbaud];
203#else
204 return tty_termios_baud_rate(termios);
205#endif
206}
Alan Coxedc6afc2006-12-08 02:38:44 -0800207EXPORT_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}
Alan Coxedc6afc2006-12-08 02:38:44 -0800341EXPORT_SYMBOL(tty_get_baud_rate);
342
Alan Coxaf9b8972006-08-27 01:24:01 -0700343/**
Alan Cox5f519d72007-10-16 23:30:07 -0700344 * tty_termios_copy_hw - copy hardware settings
345 * @new: New termios
346 * @old: Old termios
347 *
348 * Propogate the hardware specific terminal setting bits from
349 * the old termios structure to the new one. This is used in cases
350 * where the hardware does not support reconfiguration or as a helper
351 * in some cases where only minimal reconfiguration is supported
352 */
353
354void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
355{
356 /* The bits a dumb device handles in software. Smart devices need
357 to always provide a set_termios method */
358 new->c_cflag &= HUPCL | CREAD | CLOCAL;
359 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
360 new->c_ispeed = old->c_ispeed;
361 new->c_ospeed = old->c_ospeed;
362}
Alan Cox5f519d72007-10-16 23:30:07 -0700363EXPORT_SYMBOL(tty_termios_copy_hw);
364
365/**
Alan Coxbf5e5832008-01-08 14:55:51 +0000366 * tty_termios_hw_change - check for setting change
367 * @a: termios
368 * @b: termios to compare
369 *
370 * Check if any of the bits that affect a dumb device have changed
371 * between the two termios structures, or a speed change is needed.
372 */
373
374int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
375{
376 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
377 return 1;
378 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
379 return 1;
380 return 0;
381}
382EXPORT_SYMBOL(tty_termios_hw_change);
383
384/**
Alan Coxaf9b8972006-08-27 01:24:01 -0700385 * change_termios - update termios values
386 * @tty: tty to update
387 * @new_termios: desired new value
388 *
389 * Perform updates to the termios values set on this terminal. There
390 * is a bit of layering violation here with n_tty in terms of the
391 * internal knowledge of this function.
392 *
393 * Locking: termios_sem
394 */
395
Alan Cox355d95a2008-02-08 04:18:48 -0800396static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
398 int canon_change;
Alan Cox978e5952008-04-30 00:53:59 -0700399 struct ktermios old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 struct tty_ldisc *ld;
Alan Cox04f378b2008-04-30 00:53:29 -0700401 unsigned long flags;
Alan Cox355d95a2008-02-08 04:18:48 -0800402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 /*
404 * Perform the actual termios internal changes under lock.
405 */
Alan Cox355d95a2008-02-08 04:18:48 -0800406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408 /* FIXME: we need to decide on some locking/ordering semantics
409 for the set_termios notification eventually */
Arjan van de Ven5785c952006-09-29 02:00:43 -0700410 mutex_lock(&tty->termios_mutex);
Alan Cox978e5952008-04-30 00:53:59 -0700411 old_termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 *tty->termios = *new_termios;
413 unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
414 canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
415 if (canon_change) {
416 memset(&tty->read_flags, 0, sizeof tty->read_flags);
417 tty->canon_head = tty->read_tail;
418 tty->canon_data = 0;
419 tty->erasing = 0;
420 }
Alan Cox355d95a2008-02-08 04:18:48 -0800421
Alan Cox5f519d72007-10-16 23:30:07 -0700422 /* This bit should be in the ldisc code */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 if (canon_change && !L_ICANON(tty) && tty->read_cnt)
424 /* Get characters left over from canonical mode. */
425 wake_up_interruptible(&tty->read_wait);
426
427 /* See if packet mode change of state. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 if (tty->link && tty->link->packet) {
429 int old_flow = ((old_termios.c_iflag & IXON) &&
430 (old_termios.c_cc[VSTOP] == '\023') &&
431 (old_termios.c_cc[VSTART] == '\021'));
432 int new_flow = (I_IXON(tty) &&
433 STOP_CHAR(tty) == '\023' &&
434 START_CHAR(tty) == '\021');
435 if (old_flow != new_flow) {
Alan Cox04f378b2008-04-30 00:53:29 -0700436 spin_lock_irqsave(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
438 if (new_flow)
439 tty->ctrl_status |= TIOCPKT_DOSTOP;
440 else
441 tty->ctrl_status |= TIOCPKT_NOSTOP;
Alan Cox04f378b2008-04-30 00:53:29 -0700442 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 wake_up_interruptible(&tty->link->read_wait);
444 }
445 }
Alan Cox355d95a2008-02-08 04:18:48 -0800446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if (tty->driver->set_termios)
448 (*tty->driver->set_termios)(tty, &old_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700449 else
450 tty_termios_copy_hw(tty->termios, &old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452 ld = tty_ldisc_ref(tty);
453 if (ld != NULL) {
454 if (ld->set_termios)
455 (ld->set_termios)(tty, &old_termios);
456 tty_ldisc_deref(ld);
457 }
Arjan van de Ven5785c952006-09-29 02:00:43 -0700458 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
Alan Coxaf9b8972006-08-27 01:24:01 -0700461/**
462 * set_termios - set termios values for a tty
463 * @tty: terminal device
464 * @arg: user data
465 * @opt: option information
466 *
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200467 * Helper function to prepare termios data and run necessary other
Alan Coxaf9b8972006-08-27 01:24:01 -0700468 * functions before using change_termios to do the actual changes.
469 *
470 * Locking:
471 * Called functions take ldisc and termios_sem locks
472 */
473
Alan Cox355d95a2008-02-08 04:18:48 -0800474static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Alan Coxedc6afc2006-12-08 02:38:44 -0800476 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 struct tty_ldisc *ld;
478 int retval = tty_check_change(tty);
479
480 if (retval)
481 return retval;
482
Alan Cox978e5952008-04-30 00:53:59 -0700483 mutex_lock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800484 memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
Alan Cox978e5952008-04-30 00:53:59 -0700485 mutex_unlock(&tty->termios_mutex);
Alan Cox64bb6c52006-12-08 02:38:47 -0800486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (opt & TERMIOS_TERMIO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 if (user_termio_to_kernel_termios(&tmp_termios,
489 (struct termio __user *)arg))
490 return -EFAULT;
Alan Coxedc6afc2006-12-08 02:38:44 -0800491#ifdef TCGETS2
492 } else if (opt & TERMIOS_OLD) {
Alan Coxedc6afc2006-12-08 02:38:44 -0800493 if (user_termios_to_kernel_termios_1(&tmp_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 (struct termios __user *)arg))
495 return -EFAULT;
Alan Cox64bb6c52006-12-08 02:38:47 -0800496 } else {
497 if (user_termios_to_kernel_termios(&tmp_termios,
498 (struct termios2 __user *)arg))
499 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
Alan Cox64bb6c52006-12-08 02:38:47 -0800501#else
502 } else if (user_termios_to_kernel_termios(&tmp_termios,
503 (struct termios __user *)arg))
504 return -EFAULT;
505#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Alan Cox355d95a2008-02-08 04:18:48 -0800507 /* If old style Bfoo values are used then load c_ispeed/c_ospeed
508 * with the real speed so its unconditionally usable */
Alan Coxedc6afc2006-12-08 02:38:44 -0800509 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
510 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 ld = tty_ldisc_ref(tty);
Alan Cox355d95a2008-02-08 04:18:48 -0800513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (ld != NULL) {
515 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
516 ld->flush_buffer(tty);
517 tty_ldisc_deref(ld);
518 }
Alan Cox355d95a2008-02-08 04:18:48 -0800519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 if (opt & TERMIOS_WAIT) {
521 tty_wait_until_sent(tty, 0);
522 if (signal_pending(current))
523 return -EINTR;
524 }
525
526 change_termios(tty, &tmp_termios);
Alan Cox5f519d72007-10-16 23:30:07 -0700527
528 /* FIXME: Arguably if tmp_termios == tty->termios AND the
529 actual requested termios was not tmp_termios then we may
530 want to return an error as no user requested change has
531 succeeded */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return 0;
533}
534
Alan Cox355d95a2008-02-08 04:18:48 -0800535static int get_termio(struct tty_struct *tty, struct termio __user *termio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 if (kernel_termios_to_user_termio(termio, tty->termios))
538 return -EFAULT;
539 return 0;
540}
541
Alan Cox355d95a2008-02-08 04:18:48 -0800542static unsigned long inq_canon(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
544 int nr, head, tail;
545
546 if (!tty->canon_data || !tty->read_buf)
547 return 0;
548 head = tty->canon_head;
549 tail = tty->read_tail;
550 nr = (head - tail) & (N_TTY_BUF_SIZE-1);
551 /* Skip EOF-chars.. */
552 while (head != tail) {
553 if (test_bit(tail, tty->read_flags) &&
554 tty->read_buf[tail] == __DISABLED_CHAR)
555 nr--;
556 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
557 }
558 return nr;
559}
560
561#ifdef TIOCGETP
562/*
563 * These are deprecated, but there is limited support..
564 *
565 * The "sg_flags" translation is a joke..
566 */
Alan Cox355d95a2008-02-08 04:18:48 -0800567static int get_sgflags(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
569 int flags = 0;
570
571 if (!(tty->termios->c_lflag & ICANON)) {
572 if (tty->termios->c_lflag & ISIG)
573 flags |= 0x02; /* cbreak */
574 else
575 flags |= 0x20; /* raw */
576 }
577 if (tty->termios->c_lflag & ECHO)
578 flags |= 0x08; /* echo */
579 if (tty->termios->c_oflag & OPOST)
580 if (tty->termios->c_oflag & ONLCR)
581 flags |= 0x10; /* crmod */
582 return flags;
583}
584
Alan Cox355d95a2008-02-08 04:18:48 -0800585static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
587 struct sgttyb tmp;
588
Arjan van de Ven5785c952006-09-29 02:00:43 -0700589 mutex_lock(&tty->termios_mutex);
Alan Cox606d0992006-12-08 02:38:45 -0800590 tmp.sg_ispeed = tty->termios->c_ispeed;
591 tmp.sg_ospeed = tty->termios->c_ospeed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 tmp.sg_erase = tty->termios->c_cc[VERASE];
593 tmp.sg_kill = tty->termios->c_cc[VKILL];
594 tmp.sg_flags = get_sgflags(tty);
Arjan van de Ven5785c952006-09-29 02:00:43 -0700595 mutex_unlock(&tty->termios_mutex);
Alan Cox355d95a2008-02-08 04:18:48 -0800596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
598}
599
Alan Cox355d95a2008-02-08 04:18:48 -0800600static void set_sgflags(struct ktermios *termios, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 termios->c_iflag = ICRNL | IXON;
603 termios->c_oflag = 0;
604 termios->c_lflag = ISIG | ICANON;
605 if (flags & 0x02) { /* cbreak */
606 termios->c_iflag = 0;
607 termios->c_lflag &= ~ICANON;
608 }
609 if (flags & 0x08) { /* echo */
610 termios->c_lflag |= ECHO | ECHOE | ECHOK |
611 ECHOCTL | ECHOKE | IEXTEN;
612 }
613 if (flags & 0x10) { /* crmod */
614 termios->c_oflag |= OPOST | ONLCR;
615 }
616 if (flags & 0x20) { /* raw */
617 termios->c_iflag = 0;
618 termios->c_lflag &= ~(ISIG | ICANON);
619 }
620 if (!(termios->c_lflag & ICANON)) {
621 termios->c_cc[VMIN] = 1;
622 termios->c_cc[VTIME] = 0;
623 }
624}
625
Alan Coxaf9b8972006-08-27 01:24:01 -0700626/**
627 * set_sgttyb - set legacy terminal values
628 * @tty: tty structure
629 * @sgttyb: pointer to old style terminal structure
630 *
631 * Updates a terminal from the legacy BSD style terminal information
632 * structure.
633 *
634 * Locking: termios_sem
635 */
636
Alan Cox355d95a2008-02-08 04:18:48 -0800637static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639 int retval;
640 struct sgttyb tmp;
Alan Coxedc6afc2006-12-08 02:38:44 -0800641 struct ktermios termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 retval = tty_check_change(tty);
644 if (retval)
645 return retval;
Alan Cox355d95a2008-02-08 04:18:48 -0800646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
648 return -EFAULT;
649
Arjan van de Ven5785c952006-09-29 02:00:43 -0700650 mutex_lock(&tty->termios_mutex);
Jiri Slaby68043962007-07-15 23:40:18 -0700651 termios = *tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 termios.c_cc[VERASE] = tmp.sg_erase;
653 termios.c_cc[VKILL] = tmp.sg_kill;
654 set_sgflags(&termios, tmp.sg_flags);
Alan Coxedc6afc2006-12-08 02:38:44 -0800655 /* Try and encode into Bfoo format */
656#ifdef BOTHER
Alan Cox355d95a2008-02-08 04:18:48 -0800657 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
658 termios.c_ospeed);
Alan Coxedc6afc2006-12-08 02:38:44 -0800659#endif
Arjan van de Ven5785c952006-09-29 02:00:43 -0700660 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 change_termios(tty, &termios);
662 return 0;
663}
664#endif
665
666#ifdef TIOCGETC
Alan Cox355d95a2008-02-08 04:18:48 -0800667static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
669 struct tchars tmp;
670
Alan Cox978e5952008-04-30 00:53:59 -0700671 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 tmp.t_intrc = tty->termios->c_cc[VINTR];
673 tmp.t_quitc = tty->termios->c_cc[VQUIT];
674 tmp.t_startc = tty->termios->c_cc[VSTART];
675 tmp.t_stopc = tty->termios->c_cc[VSTOP];
676 tmp.t_eofc = tty->termios->c_cc[VEOF];
677 tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700678 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
680}
681
Alan Cox355d95a2008-02-08 04:18:48 -0800682static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 struct tchars tmp;
685
686 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
687 return -EFAULT;
Alan Cox978e5952008-04-30 00:53:59 -0700688 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 tty->termios->c_cc[VINTR] = tmp.t_intrc;
690 tty->termios->c_cc[VQUIT] = tmp.t_quitc;
691 tty->termios->c_cc[VSTART] = tmp.t_startc;
692 tty->termios->c_cc[VSTOP] = tmp.t_stopc;
693 tty->termios->c_cc[VEOF] = tmp.t_eofc;
694 tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
Alan Cox978e5952008-04-30 00:53:59 -0700695 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return 0;
697}
698#endif
699
700#ifdef TIOCGLTC
Alan Cox355d95a2008-02-08 04:18:48 -0800701static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 struct ltchars tmp;
704
Alan Cox978e5952008-04-30 00:53:59 -0700705 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 tmp.t_suspc = tty->termios->c_cc[VSUSP];
Alan Cox355d95a2008-02-08 04:18:48 -0800707 /* what is dsuspc anyway? */
708 tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
Alan Cox355d95a2008-02-08 04:18:48 -0800710 /* what is flushc anyway? */
711 tmp.t_flushc = tty->termios->c_cc[VEOL2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 tmp.t_werasc = tty->termios->c_cc[VWERASE];
713 tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
Alan Cox978e5952008-04-30 00:53:59 -0700714 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
716}
717
Alan Cox355d95a2008-02-08 04:18:48 -0800718static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 struct ltchars tmp;
721
722 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
723 return -EFAULT;
724
Alan Cox978e5952008-04-30 00:53:59 -0700725 mutex_lock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 tty->termios->c_cc[VSUSP] = tmp.t_suspc;
Alan Cox355d95a2008-02-08 04:18:48 -0800727 /* what is dsuspc anyway? */
728 tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
Alan Cox355d95a2008-02-08 04:18:48 -0800730 /* what is flushc anyway? */
731 tty->termios->c_cc[VEOL2] = tmp.t_flushc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 tty->termios->c_cc[VWERASE] = tmp.t_werasc;
733 tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
Alan Cox978e5952008-04-30 00:53:59 -0700734 mutex_unlock(&tty->termios_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return 0;
736}
737#endif
738
Alan Coxaf9b8972006-08-27 01:24:01 -0700739/**
740 * send_prio_char - send priority character
741 *
742 * Send a high priority character to the tty even if stopped
743 *
Alan Cox5f412b22006-09-29 02:01:40 -0700744 * Locking: none for xchar method, write ordering for write method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 */
Alan Coxaf9b8972006-08-27 01:24:01 -0700746
Alan Cox5f412b22006-09-29 02:01:40 -0700747static int send_prio_char(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 int was_stopped = tty->stopped;
750
751 if (tty->driver->send_xchar) {
752 tty->driver->send_xchar(tty, ch);
Alan Cox5f412b22006-09-29 02:01:40 -0700753 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 }
Alan Cox5f412b22006-09-29 02:01:40 -0700755
Alan Cox9c1729d2007-07-15 23:39:43 -0700756 if (tty_write_lock(tty, 0) < 0)
Alan Cox5f412b22006-09-29 02:01:40 -0700757 return -ERESTARTSYS;
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (was_stopped)
760 start_tty(tty);
761 tty->driver->write(tty, &ch, 1);
762 if (was_stopped)
763 stop_tty(tty);
Alan Cox9c1729d2007-07-15 23:39:43 -0700764 tty_write_unlock(tty);
Alan Cox5f412b22006-09-29 02:01:40 -0700765 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Alan Cox0fc00e22007-11-07 01:24:56 -0800768/**
Alan Cox1c2630c2008-04-30 00:53:34 -0700769 * tty_change_softcar - carrier change ioctl helper
770 * @tty: tty to update
771 * @arg: enable/disable CLOCAL
772 *
773 * Perform a change to the CLOCAL state and call into the driver
774 * layer to make it visible. All done with the termios mutex
775 */
776
777static int tty_change_softcar(struct tty_struct *tty, int arg)
778{
779 int ret = 0;
780 int bit = arg ? CLOCAL : 0;
781 struct ktermios old = *tty->termios;
782
783 mutex_lock(&tty->termios_mutex);
784 tty->termios->c_cflag &= ~CLOCAL;
785 tty->termios->c_cflag |= bit;
786 if (tty->driver->set_termios)
787 tty->driver->set_termios(tty, &old);
788 if ((tty->termios->c_cflag & CLOCAL) != bit)
789 ret = -EINVAL;
790 mutex_unlock(&tty->termios_mutex);
791 return ret;
792}
793
794/**
Alan Cox0fc00e22007-11-07 01:24:56 -0800795 * tty_mode_ioctl - mode related ioctls
796 * @tty: tty for the ioctl
797 * @file: file pointer for the tty
798 * @cmd: command
799 * @arg: ioctl argument
800 *
801 * Perform non line discipline specific mode control ioctls. This
802 * is designed to be called by line disciplines to ensure they provide
803 * consistent mode setting.
804 */
805
Alan Cox355d95a2008-02-08 04:18:48 -0800806int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800807 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
Alan Cox355d95a2008-02-08 04:18:48 -0800809 struct tty_struct *real_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 void __user *p = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
813 tty->driver->subtype == PTY_TYPE_MASTER)
814 real_tty = tty->link;
815 else
816 real_tty = tty;
817
818 switch (cmd) {
819#ifdef TIOCGETP
Alan Cox355d95a2008-02-08 04:18:48 -0800820 case TIOCGETP:
821 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
822 case TIOCSETP:
823 case TIOCSETN:
824 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825#endif
826#ifdef TIOCGETC
Alan Cox355d95a2008-02-08 04:18:48 -0800827 case TIOCGETC:
828 return get_tchars(real_tty, p);
829 case TIOCSETC:
830 return set_tchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831#endif
832#ifdef TIOCGLTC
Alan Cox355d95a2008-02-08 04:18:48 -0800833 case TIOCGLTC:
834 return get_ltchars(real_tty, p);
835 case TIOCSLTC:
836 return set_ltchars(real_tty, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800838 case TCSETSF:
839 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
840 case TCSETSW:
841 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
842 case TCSETS:
843 return set_termios(real_tty, p, TERMIOS_OLD);
Alan Coxedc6afc2006-12-08 02:38:44 -0800844#ifndef TCGETS2
Alan Cox355d95a2008-02-08 04:18:48 -0800845 case TCGETS:
846 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
847 return -EFAULT;
848 return 0;
Alan Coxedc6afc2006-12-08 02:38:44 -0800849#else
Alan Cox355d95a2008-02-08 04:18:48 -0800850 case TCGETS:
851 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
852 return -EFAULT;
853 return 0;
854 case TCGETS2:
855 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
856 return -EFAULT;
857 return 0;
858 case TCSETSF2:
859 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
860 case TCSETSW2:
861 return set_termios(real_tty, p, TERMIOS_WAIT);
862 case TCSETS2:
863 return set_termios(real_tty, p, 0);
Alan Coxedc6afc2006-12-08 02:38:44 -0800864#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800865 case TCGETA:
866 return get_termio(real_tty, p);
867 case TCSETAF:
868 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
869 case TCSETAW:
870 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
871 case TCSETA:
872 return set_termios(real_tty, p, TERMIOS_TERMIO);
Alan Cox0fc00e22007-11-07 01:24:56 -0800873#ifndef TCGETS2
Alan Cox355d95a2008-02-08 04:18:48 -0800874 case TIOCGLCKTRMIOS:
875 if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
876 return -EFAULT;
877 return 0;
878 case TIOCSLCKTRMIOS:
879 if (!capable(CAP_SYS_ADMIN))
880 return -EPERM;
881 if (user_termios_to_kernel_termios(real_tty->termios_locked,
882 (struct termios __user *) arg))
883 return -EFAULT;
884 return 0;
Alan Cox0fc00e22007-11-07 01:24:56 -0800885#else
Alan Cox355d95a2008-02-08 04:18:48 -0800886 case TIOCGLCKTRMIOS:
887 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
888 return -EFAULT;
889 return 0;
890 case TIOCSLCKTRMIOS:
891 if (!capable(CAP_SYS_ADMIN))
892 return -EPERM;
893 if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
894 (struct termios __user *) arg))
895 return -EFAULT;
Alan Cox0fc00e22007-11-07 01:24:56 -0800896 return 0;
897#endif
Alan Cox355d95a2008-02-08 04:18:48 -0800898 case TIOCGSOFTCAR:
899 return put_user(C_CLOCAL(tty) ? 1 : 0,
900 (int __user *)arg);
901 case TIOCSSOFTCAR:
902 if (get_user(arg, (unsigned int __user *) arg))
903 return -EFAULT;
Alan Cox1c2630c2008-04-30 00:53:34 -0700904 return tty_change_softcar(tty, arg);
Alan Cox355d95a2008-02-08 04:18:48 -0800905 default:
906 return -ENOIOCTLCMD;
Alan Cox0fc00e22007-11-07 01:24:56 -0800907 }
908}
Alan Cox0fc00e22007-11-07 01:24:56 -0800909EXPORT_SYMBOL_GPL(tty_mode_ioctl);
910
911int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
912{
913 struct tty_ldisc *ld;
914 int retval = tty_check_change(tty);
915 if (retval)
916 return retval;
917
918 ld = tty_ldisc_ref(tty);
919 switch (arg) {
920 case TCIFLUSH:
921 if (ld && ld->flush_buffer)
922 ld->flush_buffer(tty);
923 break;
924 case TCIOFLUSH:
925 if (ld && ld->flush_buffer)
926 ld->flush_buffer(tty);
927 /* fall through */
928 case TCOFLUSH:
929 if (tty->driver->flush_buffer)
930 tty->driver->flush_buffer(tty);
931 break;
932 default:
933 tty_ldisc_deref(ld);
934 return -EINVAL;
935 }
936 tty_ldisc_deref(ld);
937 return 0;
938}
Alan Cox0fc00e22007-11-07 01:24:56 -0800939EXPORT_SYMBOL_GPL(tty_perform_flush);
940
Alan Cox355d95a2008-02-08 04:18:48 -0800941int n_tty_ioctl(struct tty_struct *tty, struct file *file,
Alan Cox0fc00e22007-11-07 01:24:56 -0800942 unsigned int cmd, unsigned long arg)
943{
Alan Cox355d95a2008-02-08 04:18:48 -0800944 struct tty_struct *real_tty;
Alan Cox04f378b2008-04-30 00:53:29 -0700945 unsigned long flags;
Alan Cox0fc00e22007-11-07 01:24:56 -0800946 int retval;
947
948 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
949 tty->driver->subtype == PTY_TYPE_MASTER)
950 real_tty = tty->link;
951 else
952 real_tty = tty;
953
954 switch (cmd) {
Alan Cox355d95a2008-02-08 04:18:48 -0800955 case TCXONC:
956 retval = tty_check_change(tty);
957 if (retval)
958 return retval;
959 switch (arg) {
960 case TCOOFF:
961 if (!tty->flow_stopped) {
962 tty->flow_stopped = 1;
963 stop_tty(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 }
Alan Cox355d95a2008-02-08 04:18:48 -0800965 break;
966 case TCOON:
967 if (tty->flow_stopped) {
968 tty->flow_stopped = 0;
969 start_tty(tty);
970 }
971 break;
972 case TCIOFF:
973 if (STOP_CHAR(tty) != __DISABLED_CHAR)
974 return send_prio_char(tty, STOP_CHAR(tty));
975 break;
976 case TCION:
977 if (START_CHAR(tty) != __DISABLED_CHAR)
978 return send_prio_char(tty, START_CHAR(tty));
979 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 default:
Alan Cox355d95a2008-02-08 04:18:48 -0800981 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
Alan Cox355d95a2008-02-08 04:18:48 -0800983 return 0;
984 case TCFLSH:
985 return tty_perform_flush(tty, arg);
986 case TIOCOUTQ:
987 return put_user(tty->driver->chars_in_buffer ?
988 tty->driver->chars_in_buffer(tty) : 0,
989 (int __user *) arg);
990 case TIOCINQ:
991 retval = tty->read_cnt;
992 if (L_ICANON(tty))
993 retval = inq_canon(tty);
994 return put_user(retval, (unsigned int __user *) arg);
995 case TIOCPKT:
996 {
997 int pktmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Alan Cox355d95a2008-02-08 04:18:48 -0800999 if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
1000 tty->driver->subtype != PTY_TYPE_MASTER)
1001 return -ENOTTY;
1002 if (get_user(pktmode, (int __user *) arg))
1003 return -EFAULT;
Alan Cox04f378b2008-04-30 00:53:29 -07001004 spin_lock_irqsave(&tty->ctrl_lock, flags);
Alan Cox355d95a2008-02-08 04:18:48 -08001005 if (pktmode) {
1006 if (!tty->packet) {
1007 tty->packet = 1;
1008 tty->link->ctrl_status = 0;
1009 }
1010 } else
1011 tty->packet = 0;
Alan Cox04f378b2008-04-30 00:53:29 -07001012 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
Alan Cox355d95a2008-02-08 04:18:48 -08001013 return 0;
1014 }
1015 default:
1016 /* Try the mode commands */
1017 return tty_mode_ioctl(tty, file, cmd, arg);
1018 }
1019}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020EXPORT_SYMBOL(n_tty_ioctl);