blob: b22a61a4fbe58c0f32a6df3cbc429655c6f2a4d9 [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);
Alan Coxbdc04e32009-09-19 13:13:31 -070026 init_waitqueue_head(&port->delta_msr_wait);
Alan Cox9e485652008-10-13 10:37:07 +010027 mutex_init(&port->mutex);
Alan Cox4a90f092008-10-13 10:39:46 +010028 spin_lock_init(&port->lock);
Alan Cox9e485652008-10-13 10:37:07 +010029 port->close_delay = (50 * HZ) / 100;
30 port->closing_wait = (3000 * HZ) / 100;
31}
32EXPORT_SYMBOL(tty_port_init);
33
34int tty_port_alloc_xmit_buf(struct tty_port *port)
35{
36 /* We may sleep in get_zeroed_page() */
37 mutex_lock(&port->mutex);
38 if (port->xmit_buf == NULL)
39 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
40 mutex_unlock(&port->mutex);
41 if (port->xmit_buf == NULL)
42 return -ENOMEM;
43 return 0;
44}
45EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
46
47void tty_port_free_xmit_buf(struct tty_port *port)
48{
49 mutex_lock(&port->mutex);
50 if (port->xmit_buf != NULL) {
51 free_page((unsigned long)port->xmit_buf);
52 port->xmit_buf = NULL;
53 }
54 mutex_unlock(&port->mutex);
55}
56EXPORT_SYMBOL(tty_port_free_xmit_buf);
57
58
Alan Cox4a90f092008-10-13 10:39:46 +010059/**
60 * tty_port_tty_get - get a tty reference
61 * @port: tty port
62 *
63 * Return a refcount protected tty instance or NULL if the port is not
64 * associated with a tty (eg due to close or hangup)
65 */
66
67struct tty_struct *tty_port_tty_get(struct tty_port *port)
68{
69 unsigned long flags;
70 struct tty_struct *tty;
71
72 spin_lock_irqsave(&port->lock, flags);
73 tty = tty_kref_get(port->tty);
74 spin_unlock_irqrestore(&port->lock, flags);
75 return tty;
76}
77EXPORT_SYMBOL(tty_port_tty_get);
78
79/**
80 * tty_port_tty_set - set the tty of a port
81 * @port: tty port
82 * @tty: the tty
83 *
84 * Associate the port and tty pair. Manages any internal refcounts.
85 * Pass NULL to deassociate a port
86 */
87
88void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
89{
90 unsigned long flags;
91
92 spin_lock_irqsave(&port->lock, flags);
93 if (port->tty)
94 tty_kref_put(port->tty);
Alan Coxcb4bca32008-10-21 13:47:44 +010095 port->tty = tty_kref_get(tty);
Alan Cox4a90f092008-10-13 10:39:46 +010096 spin_unlock_irqrestore(&port->lock, flags);
97}
98EXPORT_SYMBOL(tty_port_tty_set);
Alan Cox31f35932009-01-02 13:45:05 +000099
Alan Cox7ca0ff92009-09-19 13:13:20 -0700100static void tty_port_shutdown(struct tty_port *port)
101{
Alan Cox64bc3972009-10-06 16:06:11 +0100102 mutex_lock(&port->mutex);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700103 if (port->ops->shutdown &&
Alan Stern1f5c13f2009-08-20 15:23:47 -0400104 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
Alan Cox7ca0ff92009-09-19 13:13:20 -0700105 port->ops->shutdown(port);
Alan Cox64bc3972009-10-06 16:06:11 +0100106 mutex_unlock(&port->mutex);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700107}
108
Alan Cox31f35932009-01-02 13:45:05 +0000109/**
Alan Cox3e616962009-01-02 13:45:26 +0000110 * tty_port_hangup - hangup helper
111 * @port: tty port
112 *
113 * Perform port level tty hangup flag and count changes. Drop the tty
114 * reference.
115 */
116
117void tty_port_hangup(struct tty_port *port)
118{
119 unsigned long flags;
120
121 spin_lock_irqsave(&port->lock, flags);
122 port->count = 0;
123 port->flags &= ~ASYNC_NORMAL_ACTIVE;
124 if (port->tty)
125 tty_kref_put(port->tty);
126 port->tty = NULL;
127 spin_unlock_irqrestore(&port->lock, flags);
128 wake_up_interruptible(&port->open_wait);
Alan Coxbdc04e32009-09-19 13:13:31 -0700129 wake_up_interruptible(&port->delta_msr_wait);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700130 tty_port_shutdown(port);
Alan Cox3e616962009-01-02 13:45:26 +0000131}
132EXPORT_SYMBOL(tty_port_hangup);
133
134/**
Alan Cox31f35932009-01-02 13:45:05 +0000135 * tty_port_carrier_raised - carrier raised check
136 * @port: tty port
137 *
138 * Wrapper for the carrier detect logic. For the moment this is used
139 * to hide some internal details. This will eventually become entirely
140 * internal to the tty port.
141 */
142
143int tty_port_carrier_raised(struct tty_port *port)
144{
145 if (port->ops->carrier_raised == NULL)
146 return 1;
147 return port->ops->carrier_raised(port);
148}
149EXPORT_SYMBOL(tty_port_carrier_raised);
Alan Cox5d951fb2009-01-02 13:45:19 +0000150
151/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100152 * tty_port_raise_dtr_rts - Raise DTR/RTS
Alan Cox5d951fb2009-01-02 13:45:19 +0000153 * @port: tty port
154 *
155 * Wrapper for the DTR/RTS raise logic. For the moment this is used
156 * to hide some internal details. This will eventually become entirely
157 * internal to the tty port.
158 */
159
160void tty_port_raise_dtr_rts(struct tty_port *port)
161{
Alan Coxfcc8ac12009-06-11 12:24:17 +0100162 if (port->ops->dtr_rts)
163 port->ops->dtr_rts(port, 1);
Alan Cox5d951fb2009-01-02 13:45:19 +0000164}
165EXPORT_SYMBOL(tty_port_raise_dtr_rts);
Alan Cox36c621d2009-01-02 13:46:10 +0000166
167/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100168 * tty_port_lower_dtr_rts - Lower DTR/RTS
169 * @port: tty port
170 *
171 * Wrapper for the DTR/RTS raise logic. For the moment this is used
172 * to hide some internal details. This will eventually become entirely
173 * internal to the tty port.
174 */
175
176void tty_port_lower_dtr_rts(struct tty_port *port)
177{
178 if (port->ops->dtr_rts)
179 port->ops->dtr_rts(port, 0);
180}
181EXPORT_SYMBOL(tty_port_lower_dtr_rts);
182
183/**
Alan Cox36c621d2009-01-02 13:46:10 +0000184 * tty_port_block_til_ready - Waiting logic for tty open
185 * @port: the tty port being opened
186 * @tty: the tty device being bound
187 * @filp: the file pointer of the opener
188 *
189 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
190 * Handles:
191 * - hangup (both before and during)
192 * - non blocking open
193 * - rts/dtr/dcd
194 * - signals
195 * - port flags and counts
196 *
197 * The passed tty_port must implement the carrier_raised method if it can
Alan Coxfcc8ac12009-06-11 12:24:17 +0100198 * do carrier detect and the dtr_rts method if it supports software
Alan Cox36c621d2009-01-02 13:46:10 +0000199 * management of these lines. Note that the dtr/rts raise is done each
200 * iteration as a hangup may have previously dropped them while we wait.
201 */
202
203int tty_port_block_til_ready(struct tty_port *port,
204 struct tty_struct *tty, struct file *filp)
205{
206 int do_clocal = 0, retval;
207 unsigned long flags;
Jiri Slaby6af9a432009-06-24 18:35:05 +0100208 DEFINE_WAIT(wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000209 int cd;
210
211 /* block if port is in the process of being closed */
212 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
Jiri Slaby5fc5b422009-06-11 14:32:42 +0100213 wait_event_interruptible(port->close_wait,
214 !(port->flags & ASYNC_CLOSING));
Alan Cox36c621d2009-01-02 13:46:10 +0000215 if (port->flags & ASYNC_HUP_NOTIFY)
216 return -EAGAIN;
217 else
218 return -ERESTARTSYS;
219 }
220
221 /* if non-blocking mode is set we can pass directly to open unless
222 the port has just hung up or is in another error state */
Alan Cox8627b962009-11-18 14:12:58 +0000223 if (tty->flags & (1 << TTY_IO_ERROR)) {
224 port->flags |= ASYNC_NORMAL_ACTIVE;
225 return 0;
226 }
227 if (filp->f_flags & O_NONBLOCK) {
Alan Cox4175f3e2009-10-28 21:12:32 +0100228 /* Indicate we are open */
229 if (tty->termios->c_cflag & CBAUD)
230 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000231 port->flags |= ASYNC_NORMAL_ACTIVE;
232 return 0;
233 }
234
235 if (C_CLOCAL(tty))
236 do_clocal = 1;
237
238 /* Block waiting until we can proceed. We may need to wait for the
239 carrier, but we must also wait for any close that is in progress
240 before the next open may complete */
241
242 retval = 0;
Alan Cox36c621d2009-01-02 13:46:10 +0000243
244 /* The port lock protects the port counts */
245 spin_lock_irqsave(&port->lock, flags);
246 if (!tty_hung_up_p(filp))
247 port->count--;
248 port->blocked_open++;
249 spin_unlock_irqrestore(&port->lock, flags);
250
251 while (1) {
252 /* Indicate we are open */
Alan Cox78349092009-01-02 13:46:43 +0000253 if (tty->termios->c_cflag & CBAUD)
254 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000255
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100256 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
Alan Cox36c621d2009-01-02 13:46:10 +0000257 /* Check for a hangup or uninitialised port. Return accordingly */
258 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
259 if (port->flags & ASYNC_HUP_NOTIFY)
260 retval = -EAGAIN;
261 else
262 retval = -ERESTARTSYS;
263 break;
264 }
265 /* Probe the carrier. For devices with no carrier detect this
266 will always return true */
267 cd = tty_port_carrier_raised(port);
268 if (!(port->flags & ASYNC_CLOSING) &&
269 (do_clocal || cd))
270 break;
271 if (signal_pending(current)) {
272 retval = -ERESTARTSYS;
273 break;
274 }
275 schedule();
276 }
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100277 finish_wait(&port->open_wait, &wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000278
279 /* Update counts. A parallel hangup will have set count to zero and
280 we must not mess that up further */
281 spin_lock_irqsave(&port->lock, flags);
282 if (!tty_hung_up_p(filp))
283 port->count++;
284 port->blocked_open--;
285 if (retval == 0)
286 port->flags |= ASYNC_NORMAL_ACTIVE;
287 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxecc2e052009-07-17 16:17:26 +0100288 return retval;
Alan Cox36c621d2009-01-02 13:46:10 +0000289
290}
291EXPORT_SYMBOL(tty_port_block_til_ready);
292
Alan Coxa6614992009-01-02 13:46:50 +0000293int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
294{
295 unsigned long flags;
296
297 spin_lock_irqsave(&port->lock, flags);
298 if (tty_hung_up_p(filp)) {
299 spin_unlock_irqrestore(&port->lock, flags);
300 return 0;
301 }
302
303 if( tty->count == 1 && port->count != 1) {
304 printk(KERN_WARNING
305 "tty_port_close_start: tty->count = 1 port count = %d.\n",
306 port->count);
307 port->count = 1;
308 }
309 if (--port->count < 0) {
310 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
311 port->count);
312 port->count = 0;
313 }
314
315 if (port->count) {
316 spin_unlock_irqrestore(&port->lock, flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700317 if (port->ops->drop)
318 port->ops->drop(port);
Alan Coxa6614992009-01-02 13:46:50 +0000319 return 0;
320 }
Alan Stern1f5c13f2009-08-20 15:23:47 -0400321 set_bit(ASYNCB_CLOSING, &port->flags);
Alan Coxa6614992009-01-02 13:46:50 +0000322 tty->closing = 1;
323 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxfba85e02009-01-02 13:48:39 +0000324 /* Don't block on a stalled port, just pull the chain */
325 if (tty->flow_stopped)
326 tty_driver_flush_buffer(tty);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700327 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
Alan Cox6ed1dba2009-01-02 13:48:11 +0000328 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Alan Coxa6614992009-01-02 13:46:50 +0000329 tty_wait_until_sent(tty, port->closing_wait);
Alan Cox1ec739b2009-06-11 12:25:25 +0100330 if (port->drain_delay) {
331 unsigned int bps = tty_get_baud_rate(tty);
332 long timeout;
333
334 if (bps > 1200)
335 timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
336 HZ / 10);
337 else
338 timeout = 2 * HZ;
339 schedule_timeout_interruptible(timeout);
340 }
Alan Cox7ca0ff92009-09-19 13:13:20 -0700341 /* Don't call port->drop for the last reference. Callers will want
342 to drop the last active reference in ->shutdown() or the tty
343 shutdown path */
Alan Coxa6614992009-01-02 13:46:50 +0000344 return 1;
345}
346EXPORT_SYMBOL(tty_port_close_start);
347
348void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
349{
350 unsigned long flags;
351
352 tty_ldisc_flush(tty);
353
Alan Coxfcc8ac12009-06-11 12:24:17 +0100354 if (tty->termios->c_cflag & HUPCL)
355 tty_port_lower_dtr_rts(port);
356
Alan Coxa6614992009-01-02 13:46:50 +0000357 spin_lock_irqsave(&port->lock, flags);
358 tty->closing = 0;
359
360 if (port->blocked_open) {
361 spin_unlock_irqrestore(&port->lock, flags);
362 if (port->close_delay) {
363 msleep_interruptible(
364 jiffies_to_msecs(port->close_delay));
365 }
366 spin_lock_irqsave(&port->lock, flags);
367 wake_up_interruptible(&port->open_wait);
368 }
369 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
370 wake_up_interruptible(&port->close_wait);
371 spin_unlock_irqrestore(&port->lock, flags);
372}
373EXPORT_SYMBOL(tty_port_close_end);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700374
375void tty_port_close(struct tty_port *port, struct tty_struct *tty,
376 struct file *filp)
377{
378 if (tty_port_close_start(port, tty, filp) == 0)
379 return;
380 tty_port_shutdown(port);
381 tty_port_close_end(port, tty);
382 tty_port_tty_set(port, NULL);
383}
384EXPORT_SYMBOL(tty_port_close);
Alan Cox64bc3972009-10-06 16:06:11 +0100385
386int tty_port_open(struct tty_port *port, struct tty_struct *tty,
387 struct file *filp)
388{
389 spin_lock_irq(&port->lock);
390 if (!tty_hung_up_p(filp))
391 ++port->count;
392 spin_unlock_irq(&port->lock);
393 tty_port_tty_set(port, tty);
394
395 /*
396 * Do the device-specific open only if the hardware isn't
397 * already initialized. Serialize open and shutdown using the
398 * port mutex.
399 */
400
401 mutex_lock(&port->mutex);
402
403 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
404 if (port->ops->activate) {
405 int retval = port->ops->activate(port, tty);
406 if (retval) {
407 mutex_unlock(&port->mutex);
408 return retval;
409 }
410 }
411 set_bit(ASYNCB_INITIALIZED, &port->flags);
412 }
413 mutex_unlock(&port->mutex);
414 return tty_port_block_til_ready(port, tty, filp);
415}
416
417EXPORT_SYMBOL(tty_port_open);