blob: 4e9d2b291f4a3095dd269d5f5621ccfeb5ce7942 [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 Cox44e49092009-11-30 13:16:41 +000028 mutex_init(&port->buf_mutex);
Alan Cox4a90f092008-10-13 10:39:46 +010029 spin_lock_init(&port->lock);
Alan Cox9e485652008-10-13 10:37:07 +010030 port->close_delay = (50 * HZ) / 100;
31 port->closing_wait = (3000 * HZ) / 100;
Alan Cox568aafc2009-11-30 13:17:14 +000032 kref_init(&port->kref);
Alan Cox9e485652008-10-13 10:37:07 +010033}
34EXPORT_SYMBOL(tty_port_init);
35
Jiri Slaby057eb852012-06-04 13:35:37 +020036struct device *tty_port_register_device(struct tty_port *port,
37 struct tty_driver *driver, unsigned index,
38 struct device *device)
39{
40 driver->ports[index] = port;
41 return tty_register_device(driver, index, device);
42}
43EXPORT_SYMBOL_GPL(tty_port_register_device);
44
Alan Cox9e485652008-10-13 10:37:07 +010045int tty_port_alloc_xmit_buf(struct tty_port *port)
46{
47 /* We may sleep in get_zeroed_page() */
Alan Cox44e49092009-11-30 13:16:41 +000048 mutex_lock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010049 if (port->xmit_buf == NULL)
50 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
Alan Cox44e49092009-11-30 13:16:41 +000051 mutex_unlock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010052 if (port->xmit_buf == NULL)
53 return -ENOMEM;
54 return 0;
55}
56EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
57
58void tty_port_free_xmit_buf(struct tty_port *port)
59{
Alan Cox44e49092009-11-30 13:16:41 +000060 mutex_lock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010061 if (port->xmit_buf != NULL) {
62 free_page((unsigned long)port->xmit_buf);
63 port->xmit_buf = NULL;
64 }
Alan Cox44e49092009-11-30 13:16:41 +000065 mutex_unlock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010066}
67EXPORT_SYMBOL(tty_port_free_xmit_buf);
68
Alan Cox568aafc2009-11-30 13:17:14 +000069static void tty_port_destructor(struct kref *kref)
70{
71 struct tty_port *port = container_of(kref, struct tty_port, kref);
72 if (port->xmit_buf)
73 free_page((unsigned long)port->xmit_buf);
74 if (port->ops->destruct)
75 port->ops->destruct(port);
76 else
77 kfree(port);
78}
79
80void tty_port_put(struct tty_port *port)
81{
82 if (port)
83 kref_put(&port->kref, tty_port_destructor);
84}
85EXPORT_SYMBOL(tty_port_put);
Alan Cox9e485652008-10-13 10:37:07 +010086
Alan Cox4a90f092008-10-13 10:39:46 +010087/**
88 * tty_port_tty_get - get a tty reference
89 * @port: tty port
90 *
91 * Return a refcount protected tty instance or NULL if the port is not
92 * associated with a tty (eg due to close or hangup)
93 */
94
95struct tty_struct *tty_port_tty_get(struct tty_port *port)
96{
97 unsigned long flags;
98 struct tty_struct *tty;
99
100 spin_lock_irqsave(&port->lock, flags);
101 tty = tty_kref_get(port->tty);
102 spin_unlock_irqrestore(&port->lock, flags);
103 return tty;
104}
105EXPORT_SYMBOL(tty_port_tty_get);
106
107/**
108 * tty_port_tty_set - set the tty of a port
109 * @port: tty port
110 * @tty: the tty
111 *
112 * Associate the port and tty pair. Manages any internal refcounts.
113 * Pass NULL to deassociate a port
114 */
115
116void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
117{
118 unsigned long flags;
119
120 spin_lock_irqsave(&port->lock, flags);
121 if (port->tty)
122 tty_kref_put(port->tty);
Alan Coxcb4bca32008-10-21 13:47:44 +0100123 port->tty = tty_kref_get(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100124 spin_unlock_irqrestore(&port->lock, flags);
125}
126EXPORT_SYMBOL(tty_port_tty_set);
Alan Cox31f35932009-01-02 13:45:05 +0000127
Alan Cox7ca0ff92009-09-19 13:13:20 -0700128static void tty_port_shutdown(struct tty_port *port)
129{
Alan Cox64bc3972009-10-06 16:06:11 +0100130 mutex_lock(&port->mutex);
Jason Wessel336cee42010-03-08 21:50:11 -0600131 if (port->ops->shutdown && !port->console &&
Alan Stern1f5c13f2009-08-20 15:23:47 -0400132 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
Alan Cox7ca0ff92009-09-19 13:13:20 -0700133 port->ops->shutdown(port);
Alan Cox64bc3972009-10-06 16:06:11 +0100134 mutex_unlock(&port->mutex);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700135}
136
Alan Cox31f35932009-01-02 13:45:05 +0000137/**
Alan Cox3e616962009-01-02 13:45:26 +0000138 * tty_port_hangup - hangup helper
139 * @port: tty port
140 *
141 * Perform port level tty hangup flag and count changes. Drop the tty
142 * reference.
143 */
144
145void tty_port_hangup(struct tty_port *port)
146{
147 unsigned long flags;
148
149 spin_lock_irqsave(&port->lock, flags);
150 port->count = 0;
151 port->flags &= ~ASYNC_NORMAL_ACTIVE;
Alan Coxd74e8282009-11-30 13:16:52 +0000152 if (port->tty) {
153 set_bit(TTY_IO_ERROR, &port->tty->flags);
Alan Cox3e616962009-01-02 13:45:26 +0000154 tty_kref_put(port->tty);
Alan Coxd74e8282009-11-30 13:16:52 +0000155 }
Alan Cox3e616962009-01-02 13:45:26 +0000156 port->tty = NULL;
157 spin_unlock_irqrestore(&port->lock, flags);
158 wake_up_interruptible(&port->open_wait);
Alan Coxbdc04e32009-09-19 13:13:31 -0700159 wake_up_interruptible(&port->delta_msr_wait);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700160 tty_port_shutdown(port);
Alan Cox3e616962009-01-02 13:45:26 +0000161}
162EXPORT_SYMBOL(tty_port_hangup);
163
164/**
Alan Cox31f35932009-01-02 13:45:05 +0000165 * tty_port_carrier_raised - carrier raised check
166 * @port: tty port
167 *
168 * Wrapper for the carrier detect 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
173int tty_port_carrier_raised(struct tty_port *port)
174{
175 if (port->ops->carrier_raised == NULL)
176 return 1;
177 return port->ops->carrier_raised(port);
178}
179EXPORT_SYMBOL(tty_port_carrier_raised);
Alan Cox5d951fb2009-01-02 13:45:19 +0000180
181/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100182 * tty_port_raise_dtr_rts - Raise DTR/RTS
Alan Cox5d951fb2009-01-02 13:45:19 +0000183 * @port: tty port
184 *
185 * Wrapper for the DTR/RTS raise logic. For the moment this is used
186 * to hide some internal details. This will eventually become entirely
187 * internal to the tty port.
188 */
189
190void tty_port_raise_dtr_rts(struct tty_port *port)
191{
Alan Coxfcc8ac12009-06-11 12:24:17 +0100192 if (port->ops->dtr_rts)
193 port->ops->dtr_rts(port, 1);
Alan Cox5d951fb2009-01-02 13:45:19 +0000194}
195EXPORT_SYMBOL(tty_port_raise_dtr_rts);
Alan Cox36c621d2009-01-02 13:46:10 +0000196
197/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100198 * tty_port_lower_dtr_rts - Lower DTR/RTS
199 * @port: tty port
200 *
201 * Wrapper for the DTR/RTS raise logic. For the moment this is used
202 * to hide some internal details. This will eventually become entirely
203 * internal to the tty port.
204 */
205
206void tty_port_lower_dtr_rts(struct tty_port *port)
207{
208 if (port->ops->dtr_rts)
209 port->ops->dtr_rts(port, 0);
210}
211EXPORT_SYMBOL(tty_port_lower_dtr_rts);
212
213/**
Alan Cox36c621d2009-01-02 13:46:10 +0000214 * tty_port_block_til_ready - Waiting logic for tty open
215 * @port: the tty port being opened
216 * @tty: the tty device being bound
217 * @filp: the file pointer of the opener
218 *
219 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
220 * Handles:
221 * - hangup (both before and during)
222 * - non blocking open
223 * - rts/dtr/dcd
224 * - signals
225 * - port flags and counts
226 *
227 * The passed tty_port must implement the carrier_raised method if it can
Alan Coxfcc8ac12009-06-11 12:24:17 +0100228 * do carrier detect and the dtr_rts method if it supports software
Alan Cox36c621d2009-01-02 13:46:10 +0000229 * management of these lines. Note that the dtr/rts raise is done each
230 * iteration as a hangup may have previously dropped them while we wait.
231 */
Alan Coxd774a562009-10-06 16:06:21 +0100232
Alan Cox36c621d2009-01-02 13:46:10 +0000233int tty_port_block_til_ready(struct tty_port *port,
234 struct tty_struct *tty, struct file *filp)
235{
236 int do_clocal = 0, retval;
237 unsigned long flags;
Jiri Slaby6af9a432009-06-24 18:35:05 +0100238 DEFINE_WAIT(wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000239
240 /* block if port is in the process of being closed */
241 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
Linus Torvaldsf3095322012-06-02 15:21:43 -0700242 wait_event_interruptible_tty(port->close_wait,
Jiri Slaby5fc5b422009-06-11 14:32:42 +0100243 !(port->flags & ASYNC_CLOSING));
Alan Cox36c621d2009-01-02 13:46:10 +0000244 if (port->flags & ASYNC_HUP_NOTIFY)
245 return -EAGAIN;
246 else
247 return -ERESTARTSYS;
248 }
249
250 /* if non-blocking mode is set we can pass directly to open unless
251 the port has just hung up or is in another error state */
Alan Cox8627b962009-11-18 14:12:58 +0000252 if (tty->flags & (1 << TTY_IO_ERROR)) {
253 port->flags |= ASYNC_NORMAL_ACTIVE;
254 return 0;
255 }
256 if (filp->f_flags & O_NONBLOCK) {
Alan Cox4175f3e2009-10-28 21:12:32 +0100257 /* Indicate we are open */
258 if (tty->termios->c_cflag & CBAUD)
259 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000260 port->flags |= ASYNC_NORMAL_ACTIVE;
261 return 0;
262 }
263
264 if (C_CLOCAL(tty))
265 do_clocal = 1;
266
267 /* Block waiting until we can proceed. We may need to wait for the
268 carrier, but we must also wait for any close that is in progress
269 before the next open may complete */
270
271 retval = 0;
Alan Cox36c621d2009-01-02 13:46:10 +0000272
273 /* The port lock protects the port counts */
274 spin_lock_irqsave(&port->lock, flags);
275 if (!tty_hung_up_p(filp))
276 port->count--;
277 port->blocked_open++;
278 spin_unlock_irqrestore(&port->lock, flags);
279
280 while (1) {
281 /* Indicate we are open */
Alan Cox78349092009-01-02 13:46:43 +0000282 if (tty->termios->c_cflag & CBAUD)
283 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000284
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100285 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
Alan Coxd774a562009-10-06 16:06:21 +0100286 /* Check for a hangup or uninitialised port.
287 Return accordingly */
Alan Cox36c621d2009-01-02 13:46:10 +0000288 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
289 if (port->flags & ASYNC_HUP_NOTIFY)
290 retval = -EAGAIN;
291 else
292 retval = -ERESTARTSYS;
293 break;
294 }
Jiri Slaby0eee50a2012-01-12 22:55:15 +0100295 /*
296 * Probe the carrier. For devices with no carrier detect
297 * tty_port_carrier_raised will always return true.
298 * Never ask drivers if CLOCAL is set, this causes troubles
299 * on some hardware.
300 */
Alan Cox36c621d2009-01-02 13:46:10 +0000301 if (!(port->flags & ASYNC_CLOSING) &&
Jiri Slaby0eee50a2012-01-12 22:55:15 +0100302 (do_clocal || tty_port_carrier_raised(port)))
Alan Cox36c621d2009-01-02 13:46:10 +0000303 break;
304 if (signal_pending(current)) {
305 retval = -ERESTARTSYS;
306 break;
307 }
Linus Torvaldsf3095322012-06-02 15:21:43 -0700308 tty_unlock();
Alan Cox36c621d2009-01-02 13:46:10 +0000309 schedule();
Linus Torvaldsf3095322012-06-02 15:21:43 -0700310 tty_lock();
Alan Cox36c621d2009-01-02 13:46:10 +0000311 }
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100312 finish_wait(&port->open_wait, &wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000313
314 /* Update counts. A parallel hangup will have set count to zero and
315 we must not mess that up further */
316 spin_lock_irqsave(&port->lock, flags);
317 if (!tty_hung_up_p(filp))
318 port->count++;
319 port->blocked_open--;
320 if (retval == 0)
321 port->flags |= ASYNC_NORMAL_ACTIVE;
322 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxecc2e052009-07-17 16:17:26 +0100323 return retval;
Alan Cox36c621d2009-01-02 13:46:10 +0000324}
325EXPORT_SYMBOL(tty_port_block_til_ready);
326
Alan Coxd774a562009-10-06 16:06:21 +0100327int tty_port_close_start(struct tty_port *port,
328 struct tty_struct *tty, struct file *filp)
Alan Coxa6614992009-01-02 13:46:50 +0000329{
330 unsigned long flags;
331
332 spin_lock_irqsave(&port->lock, flags);
333 if (tty_hung_up_p(filp)) {
334 spin_unlock_irqrestore(&port->lock, flags);
335 return 0;
336 }
337
Alan Coxd774a562009-10-06 16:06:21 +0100338 if (tty->count == 1 && port->count != 1) {
Alan Coxa6614992009-01-02 13:46:50 +0000339 printk(KERN_WARNING
340 "tty_port_close_start: tty->count = 1 port count = %d.\n",
341 port->count);
342 port->count = 1;
343 }
344 if (--port->count < 0) {
345 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
346 port->count);
347 port->count = 0;
348 }
349
350 if (port->count) {
351 spin_unlock_irqrestore(&port->lock, flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700352 if (port->ops->drop)
353 port->ops->drop(port);
Alan Coxa6614992009-01-02 13:46:50 +0000354 return 0;
355 }
Alan Stern1f5c13f2009-08-20 15:23:47 -0400356 set_bit(ASYNCB_CLOSING, &port->flags);
Alan Coxa6614992009-01-02 13:46:50 +0000357 tty->closing = 1;
358 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxfba85e02009-01-02 13:48:39 +0000359 /* Don't block on a stalled port, just pull the chain */
360 if (tty->flow_stopped)
361 tty_driver_flush_buffer(tty);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700362 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
Alan Cox6ed1dba2009-01-02 13:48:11 +0000363 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Jiri Slaby424cc032011-08-25 15:12:07 +0200364 tty_wait_until_sent_from_close(tty, port->closing_wait);
Alan Cox1ec739b2009-06-11 12:25:25 +0100365 if (port->drain_delay) {
366 unsigned int bps = tty_get_baud_rate(tty);
367 long timeout;
368
369 if (bps > 1200)
Alan Coxd774a562009-10-06 16:06:21 +0100370 timeout = max_t(long,
371 (HZ * 10 * port->drain_delay) / bps, HZ / 10);
Alan Cox1ec739b2009-06-11 12:25:25 +0100372 else
373 timeout = 2 * HZ;
374 schedule_timeout_interruptible(timeout);
375 }
Alan Coxe707c352009-11-05 13:27:57 +0000376 /* Flush the ldisc buffering */
377 tty_ldisc_flush(tty);
378
379 /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
380 hang up the line */
381 if (tty->termios->c_cflag & HUPCL)
382 tty_port_lower_dtr_rts(port);
383
Alan Cox7ca0ff92009-09-19 13:13:20 -0700384 /* Don't call port->drop for the last reference. Callers will want
385 to drop the last active reference in ->shutdown() or the tty
386 shutdown path */
Alan Coxa6614992009-01-02 13:46:50 +0000387 return 1;
388}
389EXPORT_SYMBOL(tty_port_close_start);
390
391void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
392{
393 unsigned long flags;
394
Alan Coxa6614992009-01-02 13:46:50 +0000395 spin_lock_irqsave(&port->lock, flags);
396 tty->closing = 0;
397
398 if (port->blocked_open) {
399 spin_unlock_irqrestore(&port->lock, flags);
400 if (port->close_delay) {
401 msleep_interruptible(
402 jiffies_to_msecs(port->close_delay));
403 }
404 spin_lock_irqsave(&port->lock, flags);
405 wake_up_interruptible(&port->open_wait);
406 }
407 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
408 wake_up_interruptible(&port->close_wait);
409 spin_unlock_irqrestore(&port->lock, flags);
410}
411EXPORT_SYMBOL(tty_port_close_end);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700412
413void tty_port_close(struct tty_port *port, struct tty_struct *tty,
414 struct file *filp)
415{
416 if (tty_port_close_start(port, tty, filp) == 0)
417 return;
418 tty_port_shutdown(port);
Alan Coxd74e8282009-11-30 13:16:52 +0000419 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700420 tty_port_close_end(port, tty);
421 tty_port_tty_set(port, NULL);
422}
423EXPORT_SYMBOL(tty_port_close);
Alan Cox64bc3972009-10-06 16:06:11 +0100424
Jiri Slaby695586c2012-06-04 13:35:32 +0200425int tty_port_install(struct tty_port *port, struct tty_driver *driver,
426 struct tty_struct *tty)
427{
428 tty->port = port;
429 return tty_standard_install(driver, tty);
430}
431EXPORT_SYMBOL_GPL(tty_port_install);
432
Alan Cox64bc3972009-10-06 16:06:11 +0100433int tty_port_open(struct tty_port *port, struct tty_struct *tty,
Alan Coxd774a562009-10-06 16:06:21 +0100434 struct file *filp)
Alan Cox64bc3972009-10-06 16:06:11 +0100435{
436 spin_lock_irq(&port->lock);
437 if (!tty_hung_up_p(filp))
438 ++port->count;
439 spin_unlock_irq(&port->lock);
440 tty_port_tty_set(port, tty);
441
442 /*
443 * Do the device-specific open only if the hardware isn't
444 * already initialized. Serialize open and shutdown using the
445 * port mutex.
446 */
447
448 mutex_lock(&port->mutex);
449
450 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
Alan Coxa9a37ec2009-11-30 13:16:57 +0000451 clear_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox64bc3972009-10-06 16:06:11 +0100452 if (port->ops->activate) {
453 int retval = port->ops->activate(port, tty);
454 if (retval) {
Alan Coxd774a562009-10-06 16:06:21 +0100455 mutex_unlock(&port->mutex);
456 return retval;
457 }
458 }
Alan Cox64bc3972009-10-06 16:06:11 +0100459 set_bit(ASYNCB_INITIALIZED, &port->flags);
460 }
461 mutex_unlock(&port->mutex);
462 return tty_port_block_til_ready(port, tty, filp);
463}
464
465EXPORT_SYMBOL(tty_port_open);