blob: 926d4a5593fac0f0d1c4033252efe32e23564a7a [file] [log] [blame]
Alan Cox9e485652008-10-13 10:37:07 +01001/*
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>
Alan Cox3e616962009-01-02 13:45:26 +000010#include <linux/serial.h>
Alan Cox9e485652008-10-13 10:37:07 +010011#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);
Alan Cox4a90f092008-10-13 10:39:46 +010027 spin_lock_init(&port->lock);
Alan Cox9e485652008-10-13 10:37:07 +010028 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
Alan Cox4a90f092008-10-13 10:39:46 +010058/**
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);
Alan Coxcb4bca32008-10-21 13:47:44 +010094 port->tty = tty_kref_get(tty);
Alan Cox4a90f092008-10-13 10:39:46 +010095 spin_unlock_irqrestore(&port->lock, flags);
96}
97EXPORT_SYMBOL(tty_port_tty_set);
Alan Cox31f35932009-01-02 13:45:05 +000098
99/**
Alan Cox3e616962009-01-02 13:45:26 +0000100 * 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
122/**
Alan Cox31f35932009-01-02 13:45:05 +0000123 * 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);
Alan Cox5d951fb2009-01-02 13:45:19 +0000138
139/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100140 * tty_port_raise_dtr_rts - Raise DTR/RTS
Alan Cox5d951fb2009-01-02 13:45:19 +0000141 * @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{
Alan Coxfcc8ac12009-06-11 12:24:17 +0100150 if (port->ops->dtr_rts)
151 port->ops->dtr_rts(port, 1);
Alan Cox5d951fb2009-01-02 13:45:19 +0000152}
153EXPORT_SYMBOL(tty_port_raise_dtr_rts);
Alan Cox36c621d2009-01-02 13:46:10 +0000154
155/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100156 * 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
171/**
Alan Cox36c621d2009-01-02 13:46:10 +0000172 * 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
Alan Coxfcc8ac12009-06-11 12:24:17 +0100186 * do carrier detect and the dtr_rts method if it supports software
Alan Cox36c621d2009-01-02 13:46:10 +0000187 * 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) {
201 interruptible_sleep_on(&port->close_wait);
202 if (port->flags & ASYNC_HUP_NOTIFY)
203 return -EAGAIN;
204 else
205 return -ERESTARTSYS;
206 }
207
208 /* if non-blocking mode is set we can pass directly to open unless
209 the port has just hung up or is in another error state */
210 if ((filp->f_flags & O_NONBLOCK) ||
211 (tty->flags & (1 << TTY_IO_ERROR))) {
212 port->flags |= ASYNC_NORMAL_ACTIVE;
213 return 0;
214 }
215
216 if (C_CLOCAL(tty))
217 do_clocal = 1;
218
219 /* Block waiting until we can proceed. We may need to wait for the
220 carrier, but we must also wait for any close that is in progress
221 before the next open may complete */
222
223 retval = 0;
224 add_wait_queue(&port->open_wait, &wait);
225
226 /* The port lock protects the port counts */
227 spin_lock_irqsave(&port->lock, flags);
228 if (!tty_hung_up_p(filp))
229 port->count--;
230 port->blocked_open++;
231 spin_unlock_irqrestore(&port->lock, flags);
232
233 while (1) {
234 /* Indicate we are open */
Alan Cox78349092009-01-02 13:46:43 +0000235 if (tty->termios->c_cflag & CBAUD)
236 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000237
238 set_current_state(TASK_INTERRUPTIBLE);
239 /* Check for a hangup or uninitialised port. Return accordingly */
240 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
241 if (port->flags & ASYNC_HUP_NOTIFY)
242 retval = -EAGAIN;
243 else
244 retval = -ERESTARTSYS;
245 break;
246 }
247 /* Probe the carrier. For devices with no carrier detect this
248 will always return true */
249 cd = tty_port_carrier_raised(port);
250 if (!(port->flags & ASYNC_CLOSING) &&
251 (do_clocal || cd))
252 break;
253 if (signal_pending(current)) {
254 retval = -ERESTARTSYS;
255 break;
256 }
257 schedule();
258 }
259 set_current_state(TASK_RUNNING);
260 remove_wait_queue(&port->open_wait, &wait);
261
262 /* Update counts. A parallel hangup will have set count to zero and
263 we must not mess that up further */
264 spin_lock_irqsave(&port->lock, flags);
265 if (!tty_hung_up_p(filp))
266 port->count++;
267 port->blocked_open--;
268 if (retval == 0)
269 port->flags |= ASYNC_NORMAL_ACTIVE;
270 spin_unlock_irqrestore(&port->lock, flags);
271 return 0;
272
273}
274EXPORT_SYMBOL(tty_port_block_til_ready);
275
Alan Coxa6614992009-01-02 13:46:50 +0000276int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
277{
278 unsigned long flags;
279
280 spin_lock_irqsave(&port->lock, flags);
281 if (tty_hung_up_p(filp)) {
282 spin_unlock_irqrestore(&port->lock, flags);
283 return 0;
284 }
285
286 if( tty->count == 1 && port->count != 1) {
287 printk(KERN_WARNING
288 "tty_port_close_start: tty->count = 1 port count = %d.\n",
289 port->count);
290 port->count = 1;
291 }
292 if (--port->count < 0) {
293 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
294 port->count);
295 port->count = 0;
296 }
297
298 if (port->count) {
299 spin_unlock_irqrestore(&port->lock, flags);
300 return 0;
301 }
302 port->flags |= ASYNC_CLOSING;
303 tty->closing = 1;
304 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxfba85e02009-01-02 13:48:39 +0000305 /* Don't block on a stalled port, just pull the chain */
306 if (tty->flow_stopped)
307 tty_driver_flush_buffer(tty);
Alan Cox6ed1dba2009-01-02 13:48:11 +0000308 if (port->flags & ASYNC_INITIALIZED &&
309 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Alan Coxa6614992009-01-02 13:46:50 +0000310 tty_wait_until_sent(tty, port->closing_wait);
311 return 1;
312}
313EXPORT_SYMBOL(tty_port_close_start);
314
315void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
316{
317 unsigned long flags;
318
319 tty_ldisc_flush(tty);
320
Alan Coxfcc8ac12009-06-11 12:24:17 +0100321 if (tty->termios->c_cflag & HUPCL)
322 tty_port_lower_dtr_rts(port);
323
Alan Coxa6614992009-01-02 13:46:50 +0000324 spin_lock_irqsave(&port->lock, flags);
325 tty->closing = 0;
326
327 if (port->blocked_open) {
328 spin_unlock_irqrestore(&port->lock, flags);
329 if (port->close_delay) {
330 msleep_interruptible(
331 jiffies_to_msecs(port->close_delay));
332 }
333 spin_lock_irqsave(&port->lock, flags);
334 wake_up_interruptible(&port->open_wait);
335 }
336 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
337 wake_up_interruptible(&port->close_wait);
338 spin_unlock_irqrestore(&port->lock, flags);
339}
340EXPORT_SYMBOL(tty_port_close_end);