compat: backport tty_set_termios
[~emulex/for-vlad/old/compat.git] / compat / compat-2.6.39.c
1 /*
2  * Copyright 2011    Hauke Mehrtens <hauke@hauke-m.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Compatibility file for Linux wireless for kernels 2.6.39.
9  */
10
11 #include <linux/compat.h>
12 #include <linux/tty.h>
13
14 /*
15  *              Termios Helper Methods
16  */
17 static void unset_locked_termios(struct ktermios *termios,
18                                  struct ktermios *old,
19                                  struct ktermios *locked)
20 {
21         int     i;
22
23 #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
24
25         if (!locked) {
26                 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
27                 return;
28         }
29
30         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
31         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
32         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
33         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
34         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
35         for (i = 0; i < NCCS; i++)
36                 termios->c_cc[i] = locked->c_cc[i] ?
37                         old->c_cc[i] : termios->c_cc[i];
38         /* FIXME: What should we do for i/ospeed */
39 }
40
41 /**
42  *      tty_set_termios         -       update termios values
43  *      @tty: tty to update
44  *      @new_termios: desired new value
45  *
46  *      Perform updates to the termios values set on this terminal. There
47  *      is a bit of layering violation here with n_tty in terms of the
48  *      internal knowledge of this function.
49  *
50  *      Locking: termios_mutex
51  */
52 int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
53 {
54         struct ktermios old_termios;
55         struct tty_ldisc *ld;
56         unsigned long flags;
57
58         /*
59          *      Perform the actual termios internal changes under lock.
60          */
61
62
63         /* FIXME: we need to decide on some locking/ordering semantics
64            for the set_termios notification eventually */
65         mutex_lock(&tty->termios_mutex);
66         old_termios = *tty->termios;
67         *tty->termios = *new_termios;
68         unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
69
70         /* See if packet mode change of state. */
71         if (tty->link && tty->link->packet) {
72                 int extproc = (old_termios.c_lflag & EXTPROC) |
73                                 (tty->termios->c_lflag & EXTPROC);
74                 int old_flow = ((old_termios.c_iflag & IXON) &&
75                                 (old_termios.c_cc[VSTOP] == '\023') &&
76                                 (old_termios.c_cc[VSTART] == '\021'));
77                 int new_flow = (I_IXON(tty) &&
78                                 STOP_CHAR(tty) == '\023' &&
79                                 START_CHAR(tty) == '\021');
80                 if ((old_flow != new_flow) || extproc) {
81                         spin_lock_irqsave(&tty->ctrl_lock, flags);
82                         if (old_flow != new_flow) {
83                                 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
84                                 if (new_flow)
85                                         tty->ctrl_status |= TIOCPKT_DOSTOP;
86                                 else
87                                         tty->ctrl_status |= TIOCPKT_NOSTOP;
88                         }
89                         if (extproc)
90                                 tty->ctrl_status |= TIOCPKT_IOCTL;
91                         spin_unlock_irqrestore(&tty->ctrl_lock, flags);
92                         wake_up_interruptible(&tty->link->read_wait);
93                 }
94         }
95
96         if (tty->ops->set_termios)
97                 (*tty->ops->set_termios)(tty, &old_termios);
98         else
99                 tty_termios_copy_hw(tty->termios, &old_termios);
100
101         ld = tty_ldisc_ref(tty);
102         if (ld != NULL) {
103                 if (ld->ops->set_termios)
104                         (ld->ops->set_termios)(tty, &old_termios);
105                 tty_ldisc_deref(ld);
106         }
107         mutex_unlock(&tty->termios_mutex);
108         return 0;
109 }
110 EXPORT_SYMBOL_GPL(tty_set_termios);
111