compat: add tty_set_termios only for kernel >= 2.6.27
[~tnikolova/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 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
15 /*
16  *              Termios Helper Methods
17  */
18 static void unset_locked_termios(struct ktermios *termios,
19                                  struct ktermios *old,
20                                  struct ktermios *locked)
21 {
22         int     i;
23
24 #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
25
26         if (!locked) {
27                 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
28                 return;
29         }
30
31         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
32         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
33         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
34         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
35         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
36         for (i = 0; i < NCCS; i++)
37                 termios->c_cc[i] = locked->c_cc[i] ?
38                         old->c_cc[i] : termios->c_cc[i];
39         /* FIXME: What should we do for i/ospeed */
40 }
41
42 /**
43  *      tty_set_termios         -       update termios values
44  *      @tty: tty to update
45  *      @new_termios: desired new value
46  *
47  *      Perform updates to the termios values set on this terminal. There
48  *      is a bit of layering violation here with n_tty in terms of the
49  *      internal knowledge of this function.
50  *
51  *      Locking: termios_mutex
52  */
53 int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
54 {
55         struct ktermios old_termios;
56         struct tty_ldisc *ld;
57         unsigned long flags;
58
59         /*
60          *      Perform the actual termios internal changes under lock.
61          */
62
63
64         /* FIXME: we need to decide on some locking/ordering semantics
65            for the set_termios notification eventually */
66         mutex_lock(&tty->termios_mutex);
67         old_termios = *tty->termios;
68         *tty->termios = *new_termios;
69         unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
70
71         /* See if packet mode change of state. */
72         if (tty->link && tty->link->packet) {
73                 int extproc = (old_termios.c_lflag & EXTPROC) |
74                                 (tty->termios->c_lflag & EXTPROC);
75                 int old_flow = ((old_termios.c_iflag & IXON) &&
76                                 (old_termios.c_cc[VSTOP] == '\023') &&
77                                 (old_termios.c_cc[VSTART] == '\021'));
78                 int new_flow = (I_IXON(tty) &&
79                                 STOP_CHAR(tty) == '\023' &&
80                                 START_CHAR(tty) == '\021');
81                 if ((old_flow != new_flow) || extproc) {
82                         spin_lock_irqsave(&tty->ctrl_lock, flags);
83                         if (old_flow != new_flow) {
84                                 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
85                                 if (new_flow)
86                                         tty->ctrl_status |= TIOCPKT_DOSTOP;
87                                 else
88                                         tty->ctrl_status |= TIOCPKT_NOSTOP;
89                         }
90                         if (extproc)
91                                 tty->ctrl_status |= TIOCPKT_IOCTL;
92                         spin_unlock_irqrestore(&tty->ctrl_lock, flags);
93                         wake_up_interruptible(&tty->link->read_wait);
94                 }
95         }
96
97         if (tty->ops->set_termios)
98                 (*tty->ops->set_termios)(tty, &old_termios);
99         else
100                 tty_termios_copy_hw(tty->termios, &old_termios);
101
102         ld = tty_ldisc_ref(tty);
103         if (ld != NULL) {
104                 if (ld->ops->set_termios)
105                         (ld->ops->set_termios)(tty, &old_termios);
106                 tty_ldisc_deref(ld);
107         }
108         mutex_unlock(&tty->termios_mutex);
109         return 0;
110 }
111 EXPORT_SYMBOL_GPL(tty_set_termios);
112 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */
113