]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/char/tty_port.c
tty: remove sleep_on
[mirror_ubuntu-hirsute-kernel.git] / drivers / char / tty_port.c
CommitLineData
9e48565d
AC
1/*
2 * Tty port functions
3 */
4
5#include <linux/types.h>
6#include <linux/errno.h>
7#include <linux/tty.h>
8#include <linux/tty_driver.h>
9#include <linux/tty_flip.h>
3e61696b 10#include <linux/serial.h>
9e48565d
AC
11#include <linux/timer.h>
12#include <linux/string.h>
13#include <linux/slab.h>
14#include <linux/sched.h>
15#include <linux/init.h>
16#include <linux/wait.h>
17#include <linux/bitops.h>
18#include <linux/delay.h>
19#include <linux/module.h>
20
21void tty_port_init(struct tty_port *port)
22{
23 memset(port, 0, sizeof(*port));
24 init_waitqueue_head(&port->open_wait);
25 init_waitqueue_head(&port->close_wait);
26 mutex_init(&port->mutex);
4a90f09b 27 spin_lock_init(&port->lock);
9e48565d
AC
28 port->close_delay = (50 * HZ) / 100;
29 port->closing_wait = (3000 * HZ) / 100;
30}
31EXPORT_SYMBOL(tty_port_init);
32
33int tty_port_alloc_xmit_buf(struct tty_port *port)
34{
35 /* We may sleep in get_zeroed_page() */
36 mutex_lock(&port->mutex);
37 if (port->xmit_buf == NULL)
38 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
39 mutex_unlock(&port->mutex);
40 if (port->xmit_buf == NULL)
41 return -ENOMEM;
42 return 0;
43}
44EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
45
46void tty_port_free_xmit_buf(struct tty_port *port)
47{
48 mutex_lock(&port->mutex);
49 if (port->xmit_buf != NULL) {
50 free_page((unsigned long)port->xmit_buf);
51 port->xmit_buf = NULL;
52 }
53 mutex_unlock(&port->mutex);
54}
55EXPORT_SYMBOL(tty_port_free_xmit_buf);
56
57
4a90f09b
AC
58/**
59 * tty_port_tty_get - get a tty reference
60 * @port: tty port
61 *
62 * Return a refcount protected tty instance or NULL if the port is not
63 * associated with a tty (eg due to close or hangup)
64 */
65
66struct tty_struct *tty_port_tty_get(struct tty_port *port)
67{
68 unsigned long flags;
69 struct tty_struct *tty;
70
71 spin_lock_irqsave(&port->lock, flags);
72 tty = tty_kref_get(port->tty);
73 spin_unlock_irqrestore(&port->lock, flags);
74 return tty;
75}
76EXPORT_SYMBOL(tty_port_tty_get);
77
78/**
79 * tty_port_tty_set - set the tty of a port
80 * @port: tty port
81 * @tty: the tty
82 *
83 * Associate the port and tty pair. Manages any internal refcounts.
84 * Pass NULL to deassociate a port
85 */
86
87void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
88{
89 unsigned long flags;
90
91 spin_lock_irqsave(&port->lock, flags);
92 if (port->tty)
93 tty_kref_put(port->tty);
cb4bca35 94 port->tty = tty_kref_get(tty);
4a90f09b
AC
95 spin_unlock_irqrestore(&port->lock, flags);
96}
97EXPORT_SYMBOL(tty_port_tty_set);
31f35939 98
3e61696b
AC
99/**
100 * tty_port_hangup - hangup helper
101 * @port: tty port
102 *
103 * Perform port level tty hangup flag and count changes. Drop the tty
104 * reference.
105 */
106
107void tty_port_hangup(struct tty_port *port)
108{
109 unsigned long flags;
110
111 spin_lock_irqsave(&port->lock, flags);
112 port->count = 0;
113 port->flags &= ~ASYNC_NORMAL_ACTIVE;
114 if (port->tty)
115 tty_kref_put(port->tty);
116 port->tty = NULL;
117 spin_unlock_irqrestore(&port->lock, flags);
118 wake_up_interruptible(&port->open_wait);
119}
120EXPORT_SYMBOL(tty_port_hangup);
121
31f35939
AC
122/**
123 * tty_port_carrier_raised - carrier raised check
124 * @port: tty port
125 *
126 * Wrapper for the carrier detect logic. For the moment this is used
127 * to hide some internal details. This will eventually become entirely
128 * internal to the tty port.
129 */
130
131int tty_port_carrier_raised(struct tty_port *port)
132{
133 if (port->ops->carrier_raised == NULL)
134 return 1;
135 return port->ops->carrier_raised(port);
136}
137EXPORT_SYMBOL(tty_port_carrier_raised);
5d951fb4
AC
138
139/**
fcc8ac18 140 * tty_port_raise_dtr_rts - Raise DTR/RTS
5d951fb4
AC
141 * @port: tty port
142 *
143 * Wrapper for the DTR/RTS raise logic. For the moment this is used
144 * to hide some internal details. This will eventually become entirely
145 * internal to the tty port.
146 */
147
148void tty_port_raise_dtr_rts(struct tty_port *port)
149{
fcc8ac18
AC
150 if (port->ops->dtr_rts)
151 port->ops->dtr_rts(port, 1);
5d951fb4
AC
152}
153EXPORT_SYMBOL(tty_port_raise_dtr_rts);
36c621d8 154
fcc8ac18
AC
155/**
156 * tty_port_lower_dtr_rts - Lower DTR/RTS
157 * @port: tty port
158 *
159 * Wrapper for the DTR/RTS raise logic. For the moment this is used
160 * to hide some internal details. This will eventually become entirely
161 * internal to the tty port.
162 */
163
164void tty_port_lower_dtr_rts(struct tty_port *port)
165{
166 if (port->ops->dtr_rts)
167 port->ops->dtr_rts(port, 0);
168}
169EXPORT_SYMBOL(tty_port_lower_dtr_rts);
170
36c621d8
AC
171/**
172 * tty_port_block_til_ready - Waiting logic for tty open
173 * @port: the tty port being opened
174 * @tty: the tty device being bound
175 * @filp: the file pointer of the opener
176 *
177 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
178 * Handles:
179 * - hangup (both before and during)
180 * - non blocking open
181 * - rts/dtr/dcd
182 * - signals
183 * - port flags and counts
184 *
185 * The passed tty_port must implement the carrier_raised method if it can
fcc8ac18 186 * do carrier detect and the dtr_rts method if it supports software
36c621d8
AC
187 * management of these lines. Note that the dtr/rts raise is done each
188 * iteration as a hangup may have previously dropped them while we wait.
189 */
190
191int tty_port_block_til_ready(struct tty_port *port,
192 struct tty_struct *tty, struct file *filp)
193{
194 int do_clocal = 0, retval;
195 unsigned long flags;
196 DECLARE_WAITQUEUE(wait, current);
197 int cd;
198
199 /* block if port is in the process of being closed */
200 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
5fc5b42a
JS
201 wait_event_interruptible(port->close_wait,
202 !(port->flags & ASYNC_CLOSING));
36c621d8
AC
203 if (port->flags & ASYNC_HUP_NOTIFY)
204 return -EAGAIN;
205 else
206 return -ERESTARTSYS;
207 }
208
209 /* if non-blocking mode is set we can pass directly to open unless
210 the port has just hung up or is in another error state */
211 if ((filp->f_flags & O_NONBLOCK) ||
212 (tty->flags & (1 << TTY_IO_ERROR))) {
213 port->flags |= ASYNC_NORMAL_ACTIVE;
214 return 0;
215 }
216
217 if (C_CLOCAL(tty))
218 do_clocal = 1;
219
220 /* Block waiting until we can proceed. We may need to wait for the
221 carrier, but we must also wait for any close that is in progress
222 before the next open may complete */
223
224 retval = 0;
225 add_wait_queue(&port->open_wait, &wait);
226
227 /* The port lock protects the port counts */
228 spin_lock_irqsave(&port->lock, flags);
229 if (!tty_hung_up_p(filp))
230 port->count--;
231 port->blocked_open++;
232 spin_unlock_irqrestore(&port->lock, flags);
233
234 while (1) {
235 /* Indicate we are open */
7834909f
AC
236 if (tty->termios->c_cflag & CBAUD)
237 tty_port_raise_dtr_rts(port);
36c621d8
AC
238
239 set_current_state(TASK_INTERRUPTIBLE);
240 /* Check for a hangup or uninitialised port. Return accordingly */
241 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
242 if (port->flags & ASYNC_HUP_NOTIFY)
243 retval = -EAGAIN;
244 else
245 retval = -ERESTARTSYS;
246 break;
247 }
248 /* Probe the carrier. For devices with no carrier detect this
249 will always return true */
250 cd = tty_port_carrier_raised(port);
251 if (!(port->flags & ASYNC_CLOSING) &&
252 (do_clocal || cd))
253 break;
254 if (signal_pending(current)) {
255 retval = -ERESTARTSYS;
256 break;
257 }
258 schedule();
259 }
260 set_current_state(TASK_RUNNING);
261 remove_wait_queue(&port->open_wait, &wait);
262
263 /* Update counts. A parallel hangup will have set count to zero and
264 we must not mess that up further */
265 spin_lock_irqsave(&port->lock, flags);
266 if (!tty_hung_up_p(filp))
267 port->count++;
268 port->blocked_open--;
269 if (retval == 0)
270 port->flags |= ASYNC_NORMAL_ACTIVE;
271 spin_unlock_irqrestore(&port->lock, flags);
272 return 0;
273
274}
275EXPORT_SYMBOL(tty_port_block_til_ready);
276
a6614999
AC
277int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
278{
279 unsigned long flags;
280
281 spin_lock_irqsave(&port->lock, flags);
282 if (tty_hung_up_p(filp)) {
283 spin_unlock_irqrestore(&port->lock, flags);
284 return 0;
285 }
286
287 if( tty->count == 1 && port->count != 1) {
288 printk(KERN_WARNING
289 "tty_port_close_start: tty->count = 1 port count = %d.\n",
290 port->count);
291 port->count = 1;
292 }
293 if (--port->count < 0) {
294 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
295 port->count);
296 port->count = 0;
297 }
298
299 if (port->count) {
300 spin_unlock_irqrestore(&port->lock, flags);
301 return 0;
302 }
303 port->flags |= ASYNC_CLOSING;
304 tty->closing = 1;
305 spin_unlock_irqrestore(&port->lock, flags);
fba85e01
AC
306 /* Don't block on a stalled port, just pull the chain */
307 if (tty->flow_stopped)
308 tty_driver_flush_buffer(tty);
6ed1dbae
AC
309 if (port->flags & ASYNC_INITIALIZED &&
310 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
a6614999 311 tty_wait_until_sent(tty, port->closing_wait);
1ec739be
AC
312 if (port->drain_delay) {
313 unsigned int bps = tty_get_baud_rate(tty);
314 long timeout;
315
316 if (bps > 1200)
317 timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
318 HZ / 10);
319 else
320 timeout = 2 * HZ;
321 schedule_timeout_interruptible(timeout);
322 }
a6614999
AC
323 return 1;
324}
325EXPORT_SYMBOL(tty_port_close_start);
326
327void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
328{
329 unsigned long flags;
330
331 tty_ldisc_flush(tty);
332
fcc8ac18
AC
333 if (tty->termios->c_cflag & HUPCL)
334 tty_port_lower_dtr_rts(port);
335
a6614999
AC
336 spin_lock_irqsave(&port->lock, flags);
337 tty->closing = 0;
338
339 if (port->blocked_open) {
340 spin_unlock_irqrestore(&port->lock, flags);
341 if (port->close_delay) {
342 msleep_interruptible(
343 jiffies_to_msecs(port->close_delay));
344 }
345 spin_lock_irqsave(&port->lock, flags);
346 wake_up_interruptible(&port->open_wait);
347 }
348 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
349 wake_up_interruptible(&port->close_wait);
350 spin_unlock_irqrestore(&port->lock, flags);
351}
352EXPORT_SYMBOL(tty_port_close_end);