serial: replace the state mutex with the tty port mutex
[deliverable/linux.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
7ca0ff9a
AC
99static void tty_port_shutdown(struct tty_port *port)
100{
101 if (port->ops->shutdown &&
102 test_and_clear_bit(ASYNC_INITIALIZED, &port->flags))
103 port->ops->shutdown(port);
104
105}
106
3e61696b
AC
107/**
108 * tty_port_hangup - hangup helper
109 * @port: tty port
110 *
111 * Perform port level tty hangup flag and count changes. Drop the tty
112 * reference.
113 */
114
115void tty_port_hangup(struct tty_port *port)
116{
117 unsigned long flags;
118
119 spin_lock_irqsave(&port->lock, flags);
120 port->count = 0;
121 port->flags &= ~ASYNC_NORMAL_ACTIVE;
122 if (port->tty)
123 tty_kref_put(port->tty);
124 port->tty = NULL;
125 spin_unlock_irqrestore(&port->lock, flags);
126 wake_up_interruptible(&port->open_wait);
7ca0ff9a 127 tty_port_shutdown(port);
3e61696b
AC
128}
129EXPORT_SYMBOL(tty_port_hangup);
130
31f35939
AC
131/**
132 * tty_port_carrier_raised - carrier raised check
133 * @port: tty port
134 *
135 * Wrapper for the carrier detect logic. For the moment this is used
136 * to hide some internal details. This will eventually become entirely
137 * internal to the tty port.
138 */
139
140int tty_port_carrier_raised(struct tty_port *port)
141{
142 if (port->ops->carrier_raised == NULL)
143 return 1;
144 return port->ops->carrier_raised(port);
145}
146EXPORT_SYMBOL(tty_port_carrier_raised);
5d951fb4
AC
147
148/**
fcc8ac18 149 * tty_port_raise_dtr_rts - Raise DTR/RTS
5d951fb4
AC
150 * @port: tty port
151 *
152 * Wrapper for the DTR/RTS raise logic. For the moment this is used
153 * to hide some internal details. This will eventually become entirely
154 * internal to the tty port.
155 */
156
157void tty_port_raise_dtr_rts(struct tty_port *port)
158{
fcc8ac18
AC
159 if (port->ops->dtr_rts)
160 port->ops->dtr_rts(port, 1);
5d951fb4
AC
161}
162EXPORT_SYMBOL(tty_port_raise_dtr_rts);
36c621d8 163
fcc8ac18
AC
164/**
165 * tty_port_lower_dtr_rts - Lower DTR/RTS
166 * @port: tty port
167 *
168 * Wrapper for the DTR/RTS raise logic. For the moment this is used
169 * to hide some internal details. This will eventually become entirely
170 * internal to the tty port.
171 */
172
173void tty_port_lower_dtr_rts(struct tty_port *port)
174{
175 if (port->ops->dtr_rts)
176 port->ops->dtr_rts(port, 0);
177}
178EXPORT_SYMBOL(tty_port_lower_dtr_rts);
179
36c621d8
AC
180/**
181 * tty_port_block_til_ready - Waiting logic for tty open
182 * @port: the tty port being opened
183 * @tty: the tty device being bound
184 * @filp: the file pointer of the opener
185 *
186 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
187 * Handles:
188 * - hangup (both before and during)
189 * - non blocking open
190 * - rts/dtr/dcd
191 * - signals
192 * - port flags and counts
193 *
194 * The passed tty_port must implement the carrier_raised method if it can
fcc8ac18 195 * do carrier detect and the dtr_rts method if it supports software
36c621d8
AC
196 * management of these lines. Note that the dtr/rts raise is done each
197 * iteration as a hangup may have previously dropped them while we wait.
198 */
199
200int tty_port_block_til_ready(struct tty_port *port,
201 struct tty_struct *tty, struct file *filp)
202{
203 int do_clocal = 0, retval;
204 unsigned long flags;
6af9a43d 205 DEFINE_WAIT(wait);
36c621d8
AC
206 int cd;
207
208 /* block if port is in the process of being closed */
209 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
5fc5b42a
JS
210 wait_event_interruptible(port->close_wait,
211 !(port->flags & ASYNC_CLOSING));
36c621d8
AC
212 if (port->flags & ASYNC_HUP_NOTIFY)
213 return -EAGAIN;
214 else
215 return -ERESTARTSYS;
216 }
217
218 /* if non-blocking mode is set we can pass directly to open unless
219 the port has just hung up or is in another error state */
220 if ((filp->f_flags & O_NONBLOCK) ||
221 (tty->flags & (1 << TTY_IO_ERROR))) {
222 port->flags |= ASYNC_NORMAL_ACTIVE;
223 return 0;
224 }
225
226 if (C_CLOCAL(tty))
227 do_clocal = 1;
228
229 /* Block waiting until we can proceed. We may need to wait for the
230 carrier, but we must also wait for any close that is in progress
231 before the next open may complete */
232
233 retval = 0;
36c621d8
AC
234
235 /* The port lock protects the port counts */
236 spin_lock_irqsave(&port->lock, flags);
237 if (!tty_hung_up_p(filp))
238 port->count--;
239 port->blocked_open++;
240 spin_unlock_irqrestore(&port->lock, flags);
241
242 while (1) {
243 /* Indicate we are open */
7834909f
AC
244 if (tty->termios->c_cflag & CBAUD)
245 tty_port_raise_dtr_rts(port);
36c621d8 246
3e3b5c08 247 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
36c621d8
AC
248 /* Check for a hangup or uninitialised port. Return accordingly */
249 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
250 if (port->flags & ASYNC_HUP_NOTIFY)
251 retval = -EAGAIN;
252 else
253 retval = -ERESTARTSYS;
254 break;
255 }
256 /* Probe the carrier. For devices with no carrier detect this
257 will always return true */
258 cd = tty_port_carrier_raised(port);
259 if (!(port->flags & ASYNC_CLOSING) &&
260 (do_clocal || cd))
261 break;
262 if (signal_pending(current)) {
263 retval = -ERESTARTSYS;
264 break;
265 }
266 schedule();
267 }
3e3b5c08 268 finish_wait(&port->open_wait, &wait);
36c621d8
AC
269
270 /* Update counts. A parallel hangup will have set count to zero and
271 we must not mess that up further */
272 spin_lock_irqsave(&port->lock, flags);
273 if (!tty_hung_up_p(filp))
274 port->count++;
275 port->blocked_open--;
276 if (retval == 0)
277 port->flags |= ASYNC_NORMAL_ACTIVE;
278 spin_unlock_irqrestore(&port->lock, flags);
ecc2e05e 279 return retval;
36c621d8
AC
280
281}
282EXPORT_SYMBOL(tty_port_block_til_ready);
283
a6614999
AC
284int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
285{
286 unsigned long flags;
287
288 spin_lock_irqsave(&port->lock, flags);
289 if (tty_hung_up_p(filp)) {
290 spin_unlock_irqrestore(&port->lock, flags);
291 return 0;
292 }
293
294 if( tty->count == 1 && port->count != 1) {
295 printk(KERN_WARNING
296 "tty_port_close_start: tty->count = 1 port count = %d.\n",
297 port->count);
298 port->count = 1;
299 }
300 if (--port->count < 0) {
301 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
302 port->count);
303 port->count = 0;
304 }
305
306 if (port->count) {
307 spin_unlock_irqrestore(&port->lock, flags);
7ca0ff9a
AC
308 if (port->ops->drop)
309 port->ops->drop(port);
a6614999
AC
310 return 0;
311 }
7ca0ff9a 312 set_bit(ASYNC_CLOSING, &port->flags);
a6614999
AC
313 tty->closing = 1;
314 spin_unlock_irqrestore(&port->lock, flags);
fba85e01
AC
315 /* Don't block on a stalled port, just pull the chain */
316 if (tty->flow_stopped)
317 tty_driver_flush_buffer(tty);
7ca0ff9a 318 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
6ed1dbae 319 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
a6614999 320 tty_wait_until_sent(tty, port->closing_wait);
1ec739be
AC
321 if (port->drain_delay) {
322 unsigned int bps = tty_get_baud_rate(tty);
323 long timeout;
324
325 if (bps > 1200)
326 timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
327 HZ / 10);
328 else
329 timeout = 2 * HZ;
330 schedule_timeout_interruptible(timeout);
331 }
7ca0ff9a
AC
332 /* Don't call port->drop for the last reference. Callers will want
333 to drop the last active reference in ->shutdown() or the tty
334 shutdown path */
a6614999
AC
335 return 1;
336}
337EXPORT_SYMBOL(tty_port_close_start);
338
339void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
340{
341 unsigned long flags;
342
343 tty_ldisc_flush(tty);
344
fcc8ac18
AC
345 if (tty->termios->c_cflag & HUPCL)
346 tty_port_lower_dtr_rts(port);
347
a6614999
AC
348 spin_lock_irqsave(&port->lock, flags);
349 tty->closing = 0;
350
351 if (port->blocked_open) {
352 spin_unlock_irqrestore(&port->lock, flags);
353 if (port->close_delay) {
354 msleep_interruptible(
355 jiffies_to_msecs(port->close_delay));
356 }
357 spin_lock_irqsave(&port->lock, flags);
358 wake_up_interruptible(&port->open_wait);
359 }
360 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
361 wake_up_interruptible(&port->close_wait);
362 spin_unlock_irqrestore(&port->lock, flags);
363}
364EXPORT_SYMBOL(tty_port_close_end);
7ca0ff9a
AC
365
366void tty_port_close(struct tty_port *port, struct tty_struct *tty,
367 struct file *filp)
368{
369 if (tty_port_close_start(port, tty, filp) == 0)
370 return;
371 tty_port_shutdown(port);
372 tty_port_close_end(port, tty);
373 tty_port_tty_set(port, NULL);
374}
375EXPORT_SYMBOL(tty_port_close);
This page took 0.18177 seconds and 5 git commands to generate.