blob: c2f0592bcb2cff271cf84a9f3e2b77469b423e8d [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 Slaby72a33bf2012-08-07 21:47:49 +020036/**
37 * tty_port_register_device - register tty device
38 * @port: tty_port of the device
39 * @driver: tty_driver for this device
40 * @index: index of the tty
41 * @device: parent if exists, otherwise NULL
42 *
43 * It is the same as tty_register_device except the provided @port is linked to
44 * a concrete tty specified by @index. Use this or tty_port_install (or both).
45 * Call tty_port_link_device as a last resort.
46 */
Jiri Slaby057eb852012-06-04 13:35:37 +020047struct device *tty_port_register_device(struct tty_port *port,
48 struct tty_driver *driver, unsigned index,
49 struct device *device)
50{
51 driver->ports[index] = port;
52 return tty_register_device(driver, index, device);
53}
54EXPORT_SYMBOL_GPL(tty_port_register_device);
55
Alan Cox9e485652008-10-13 10:37:07 +010056int tty_port_alloc_xmit_buf(struct tty_port *port)
57{
58 /* We may sleep in get_zeroed_page() */
Alan Cox44e49092009-11-30 13:16:41 +000059 mutex_lock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010060 if (port->xmit_buf == NULL)
61 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
Alan Cox44e49092009-11-30 13:16:41 +000062 mutex_unlock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010063 if (port->xmit_buf == NULL)
64 return -ENOMEM;
65 return 0;
66}
67EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
68
69void tty_port_free_xmit_buf(struct tty_port *port)
70{
Alan Cox44e49092009-11-30 13:16:41 +000071 mutex_lock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010072 if (port->xmit_buf != NULL) {
73 free_page((unsigned long)port->xmit_buf);
74 port->xmit_buf = NULL;
75 }
Alan Cox44e49092009-11-30 13:16:41 +000076 mutex_unlock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010077}
78EXPORT_SYMBOL(tty_port_free_xmit_buf);
79
Alan Cox568aafc2009-11-30 13:17:14 +000080static void tty_port_destructor(struct kref *kref)
81{
82 struct tty_port *port = container_of(kref, struct tty_port, kref);
83 if (port->xmit_buf)
84 free_page((unsigned long)port->xmit_buf);
85 if (port->ops->destruct)
86 port->ops->destruct(port);
87 else
88 kfree(port);
89}
90
91void tty_port_put(struct tty_port *port)
92{
93 if (port)
94 kref_put(&port->kref, tty_port_destructor);
95}
96EXPORT_SYMBOL(tty_port_put);
Alan Cox9e485652008-10-13 10:37:07 +010097
Alan Cox4a90f092008-10-13 10:39:46 +010098/**
99 * tty_port_tty_get - get a tty reference
100 * @port: tty port
101 *
102 * Return a refcount protected tty instance or NULL if the port is not
103 * associated with a tty (eg due to close or hangup)
104 */
105
106struct tty_struct *tty_port_tty_get(struct tty_port *port)
107{
108 unsigned long flags;
109 struct tty_struct *tty;
110
111 spin_lock_irqsave(&port->lock, flags);
112 tty = tty_kref_get(port->tty);
113 spin_unlock_irqrestore(&port->lock, flags);
114 return tty;
115}
116EXPORT_SYMBOL(tty_port_tty_get);
117
118/**
119 * tty_port_tty_set - set the tty of a port
120 * @port: tty port
121 * @tty: the tty
122 *
123 * Associate the port and tty pair. Manages any internal refcounts.
124 * Pass NULL to deassociate a port
125 */
126
127void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
128{
129 unsigned long flags;
130
131 spin_lock_irqsave(&port->lock, flags);
132 if (port->tty)
133 tty_kref_put(port->tty);
Alan Coxcb4bca32008-10-21 13:47:44 +0100134 port->tty = tty_kref_get(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100135 spin_unlock_irqrestore(&port->lock, flags);
136}
137EXPORT_SYMBOL(tty_port_tty_set);
Alan Cox31f35932009-01-02 13:45:05 +0000138
Alan Cox7ca0ff92009-09-19 13:13:20 -0700139static void tty_port_shutdown(struct tty_port *port)
140{
Alan Cox64bc3972009-10-06 16:06:11 +0100141 mutex_lock(&port->mutex);
Jason Wessel336cee42010-03-08 21:50:11 -0600142 if (port->ops->shutdown && !port->console &&
Alan Stern1f5c13f2009-08-20 15:23:47 -0400143 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
Alan Cox7ca0ff92009-09-19 13:13:20 -0700144 port->ops->shutdown(port);
Alan Cox64bc3972009-10-06 16:06:11 +0100145 mutex_unlock(&port->mutex);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700146}
147
Alan Cox31f35932009-01-02 13:45:05 +0000148/**
Alan Cox3e616962009-01-02 13:45:26 +0000149 * tty_port_hangup - hangup helper
150 * @port: tty port
151 *
152 * Perform port level tty hangup flag and count changes. Drop the tty
153 * reference.
154 */
155
156void tty_port_hangup(struct tty_port *port)
157{
158 unsigned long flags;
159
160 spin_lock_irqsave(&port->lock, flags);
161 port->count = 0;
162 port->flags &= ~ASYNC_NORMAL_ACTIVE;
Alan Coxd74e8282009-11-30 13:16:52 +0000163 if (port->tty) {
164 set_bit(TTY_IO_ERROR, &port->tty->flags);
Alan Cox3e616962009-01-02 13:45:26 +0000165 tty_kref_put(port->tty);
Alan Coxd74e8282009-11-30 13:16:52 +0000166 }
Alan Cox3e616962009-01-02 13:45:26 +0000167 port->tty = NULL;
168 spin_unlock_irqrestore(&port->lock, flags);
169 wake_up_interruptible(&port->open_wait);
Alan Coxbdc04e32009-09-19 13:13:31 -0700170 wake_up_interruptible(&port->delta_msr_wait);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700171 tty_port_shutdown(port);
Alan Cox3e616962009-01-02 13:45:26 +0000172}
173EXPORT_SYMBOL(tty_port_hangup);
174
175/**
Alan Cox31f35932009-01-02 13:45:05 +0000176 * tty_port_carrier_raised - carrier raised check
177 * @port: tty port
178 *
179 * Wrapper for the carrier detect logic. For the moment this is used
180 * to hide some internal details. This will eventually become entirely
181 * internal to the tty port.
182 */
183
184int tty_port_carrier_raised(struct tty_port *port)
185{
186 if (port->ops->carrier_raised == NULL)
187 return 1;
188 return port->ops->carrier_raised(port);
189}
190EXPORT_SYMBOL(tty_port_carrier_raised);
Alan Cox5d951fb2009-01-02 13:45:19 +0000191
192/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100193 * tty_port_raise_dtr_rts - Raise DTR/RTS
Alan Cox5d951fb2009-01-02 13:45:19 +0000194 * @port: tty port
195 *
196 * Wrapper for the DTR/RTS raise logic. For the moment this is used
197 * to hide some internal details. This will eventually become entirely
198 * internal to the tty port.
199 */
200
201void tty_port_raise_dtr_rts(struct tty_port *port)
202{
Alan Coxfcc8ac12009-06-11 12:24:17 +0100203 if (port->ops->dtr_rts)
204 port->ops->dtr_rts(port, 1);
Alan Cox5d951fb2009-01-02 13:45:19 +0000205}
206EXPORT_SYMBOL(tty_port_raise_dtr_rts);
Alan Cox36c621d2009-01-02 13:46:10 +0000207
208/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100209 * tty_port_lower_dtr_rts - Lower DTR/RTS
210 * @port: tty port
211 *
212 * Wrapper for the DTR/RTS raise logic. For the moment this is used
213 * to hide some internal details. This will eventually become entirely
214 * internal to the tty port.
215 */
216
217void tty_port_lower_dtr_rts(struct tty_port *port)
218{
219 if (port->ops->dtr_rts)
220 port->ops->dtr_rts(port, 0);
221}
222EXPORT_SYMBOL(tty_port_lower_dtr_rts);
223
224/**
Alan Cox36c621d2009-01-02 13:46:10 +0000225 * tty_port_block_til_ready - Waiting logic for tty open
226 * @port: the tty port being opened
227 * @tty: the tty device being bound
228 * @filp: the file pointer of the opener
229 *
230 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
231 * Handles:
232 * - hangup (both before and during)
233 * - non blocking open
234 * - rts/dtr/dcd
235 * - signals
236 * - port flags and counts
237 *
238 * The passed tty_port must implement the carrier_raised method if it can
Alan Coxfcc8ac12009-06-11 12:24:17 +0100239 * do carrier detect and the dtr_rts method if it supports software
Alan Cox36c621d2009-01-02 13:46:10 +0000240 * management of these lines. Note that the dtr/rts raise is done each
241 * iteration as a hangup may have previously dropped them while we wait.
242 */
Alan Coxd774a562009-10-06 16:06:21 +0100243
Alan Cox36c621d2009-01-02 13:46:10 +0000244int tty_port_block_til_ready(struct tty_port *port,
245 struct tty_struct *tty, struct file *filp)
246{
247 int do_clocal = 0, retval;
248 unsigned long flags;
Jiri Slaby6af9a432009-06-24 18:35:05 +0100249 DEFINE_WAIT(wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000250
251 /* block if port is in the process of being closed */
252 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
Alan Cox89c8d912012-08-08 16:30:13 +0100253 wait_event_interruptible_tty(tty, port->close_wait,
Jiri Slaby5fc5b422009-06-11 14:32:42 +0100254 !(port->flags & ASYNC_CLOSING));
Alan Cox36c621d2009-01-02 13:46:10 +0000255 if (port->flags & ASYNC_HUP_NOTIFY)
256 return -EAGAIN;
257 else
258 return -ERESTARTSYS;
259 }
260
261 /* if non-blocking mode is set we can pass directly to open unless
262 the port has just hung up or is in another error state */
Alan Cox8627b962009-11-18 14:12:58 +0000263 if (tty->flags & (1 << TTY_IO_ERROR)) {
264 port->flags |= ASYNC_NORMAL_ACTIVE;
265 return 0;
266 }
267 if (filp->f_flags & O_NONBLOCK) {
Alan Cox4175f3e2009-10-28 21:12:32 +0100268 /* Indicate we are open */
Alan Coxadc8d742012-07-14 15:31:47 +0100269 if (tty->termios.c_cflag & CBAUD)
Alan Cox4175f3e2009-10-28 21:12:32 +0100270 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000271 port->flags |= ASYNC_NORMAL_ACTIVE;
272 return 0;
273 }
274
275 if (C_CLOCAL(tty))
276 do_clocal = 1;
277
278 /* Block waiting until we can proceed. We may need to wait for the
279 carrier, but we must also wait for any close that is in progress
280 before the next open may complete */
281
282 retval = 0;
Alan Cox36c621d2009-01-02 13:46:10 +0000283
284 /* The port lock protects the port counts */
285 spin_lock_irqsave(&port->lock, flags);
286 if (!tty_hung_up_p(filp))
287 port->count--;
288 port->blocked_open++;
289 spin_unlock_irqrestore(&port->lock, flags);
290
291 while (1) {
292 /* Indicate we are open */
Alan Coxadc8d742012-07-14 15:31:47 +0100293 if (tty->termios.c_cflag & CBAUD)
Alan Cox78349092009-01-02 13:46:43 +0000294 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000295
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100296 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
Alan Coxd774a562009-10-06 16:06:21 +0100297 /* Check for a hangup or uninitialised port.
298 Return accordingly */
Alan Cox36c621d2009-01-02 13:46:10 +0000299 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
300 if (port->flags & ASYNC_HUP_NOTIFY)
301 retval = -EAGAIN;
302 else
303 retval = -ERESTARTSYS;
304 break;
305 }
Jiri Slaby0eee50a2012-01-12 22:55:15 +0100306 /*
307 * Probe the carrier. For devices with no carrier detect
308 * tty_port_carrier_raised will always return true.
309 * Never ask drivers if CLOCAL is set, this causes troubles
310 * on some hardware.
311 */
Alan Cox36c621d2009-01-02 13:46:10 +0000312 if (!(port->flags & ASYNC_CLOSING) &&
Jiri Slaby0eee50a2012-01-12 22:55:15 +0100313 (do_clocal || tty_port_carrier_raised(port)))
Alan Cox36c621d2009-01-02 13:46:10 +0000314 break;
315 if (signal_pending(current)) {
316 retval = -ERESTARTSYS;
317 break;
318 }
Alan Cox89c8d912012-08-08 16:30:13 +0100319 tty_unlock(tty);
Alan Cox36c621d2009-01-02 13:46:10 +0000320 schedule();
Alan Cox89c8d912012-08-08 16:30:13 +0100321 tty_lock(tty);
Alan Cox36c621d2009-01-02 13:46:10 +0000322 }
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100323 finish_wait(&port->open_wait, &wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000324
325 /* Update counts. A parallel hangup will have set count to zero and
326 we must not mess that up further */
327 spin_lock_irqsave(&port->lock, flags);
328 if (!tty_hung_up_p(filp))
329 port->count++;
330 port->blocked_open--;
331 if (retval == 0)
332 port->flags |= ASYNC_NORMAL_ACTIVE;
333 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxecc2e052009-07-17 16:17:26 +0100334 return retval;
Alan Cox36c621d2009-01-02 13:46:10 +0000335}
336EXPORT_SYMBOL(tty_port_block_til_ready);
337
Alan Coxd774a562009-10-06 16:06:21 +0100338int tty_port_close_start(struct tty_port *port,
339 struct tty_struct *tty, struct file *filp)
Alan Coxa6614992009-01-02 13:46:50 +0000340{
341 unsigned long flags;
342
343 spin_lock_irqsave(&port->lock, flags);
344 if (tty_hung_up_p(filp)) {
345 spin_unlock_irqrestore(&port->lock, flags);
346 return 0;
347 }
348
Alan Coxd774a562009-10-06 16:06:21 +0100349 if (tty->count == 1 && port->count != 1) {
Alan Coxa6614992009-01-02 13:46:50 +0000350 printk(KERN_WARNING
351 "tty_port_close_start: tty->count = 1 port count = %d.\n",
352 port->count);
353 port->count = 1;
354 }
355 if (--port->count < 0) {
356 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
357 port->count);
358 port->count = 0;
359 }
360
361 if (port->count) {
362 spin_unlock_irqrestore(&port->lock, flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700363 if (port->ops->drop)
364 port->ops->drop(port);
Alan Coxa6614992009-01-02 13:46:50 +0000365 return 0;
366 }
Alan Stern1f5c13f2009-08-20 15:23:47 -0400367 set_bit(ASYNCB_CLOSING, &port->flags);
Alan Coxa6614992009-01-02 13:46:50 +0000368 tty->closing = 1;
369 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxfba85e02009-01-02 13:48:39 +0000370 /* Don't block on a stalled port, just pull the chain */
371 if (tty->flow_stopped)
372 tty_driver_flush_buffer(tty);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700373 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
Alan Cox6ed1dba2009-01-02 13:48:11 +0000374 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Jiri Slaby424cc032011-08-25 15:12:07 +0200375 tty_wait_until_sent_from_close(tty, port->closing_wait);
Alan Cox1ec739b2009-06-11 12:25:25 +0100376 if (port->drain_delay) {
377 unsigned int bps = tty_get_baud_rate(tty);
378 long timeout;
379
380 if (bps > 1200)
Alan Coxd774a562009-10-06 16:06:21 +0100381 timeout = max_t(long,
382 (HZ * 10 * port->drain_delay) / bps, HZ / 10);
Alan Cox1ec739b2009-06-11 12:25:25 +0100383 else
384 timeout = 2 * HZ;
385 schedule_timeout_interruptible(timeout);
386 }
Alan Coxe707c352009-11-05 13:27:57 +0000387 /* Flush the ldisc buffering */
388 tty_ldisc_flush(tty);
389
390 /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
391 hang up the line */
Alan Coxadc8d742012-07-14 15:31:47 +0100392 if (tty->termios.c_cflag & HUPCL)
Alan Coxe707c352009-11-05 13:27:57 +0000393 tty_port_lower_dtr_rts(port);
394
Alan Cox7ca0ff92009-09-19 13:13:20 -0700395 /* Don't call port->drop for the last reference. Callers will want
396 to drop the last active reference in ->shutdown() or the tty
397 shutdown path */
Alan Coxa6614992009-01-02 13:46:50 +0000398 return 1;
399}
400EXPORT_SYMBOL(tty_port_close_start);
401
402void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
403{
404 unsigned long flags;
405
Alan Coxa6614992009-01-02 13:46:50 +0000406 spin_lock_irqsave(&port->lock, flags);
407 tty->closing = 0;
408
409 if (port->blocked_open) {
410 spin_unlock_irqrestore(&port->lock, flags);
411 if (port->close_delay) {
412 msleep_interruptible(
413 jiffies_to_msecs(port->close_delay));
414 }
415 spin_lock_irqsave(&port->lock, flags);
416 wake_up_interruptible(&port->open_wait);
417 }
418 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
419 wake_up_interruptible(&port->close_wait);
420 spin_unlock_irqrestore(&port->lock, flags);
421}
422EXPORT_SYMBOL(tty_port_close_end);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700423
424void tty_port_close(struct tty_port *port, struct tty_struct *tty,
425 struct file *filp)
426{
427 if (tty_port_close_start(port, tty, filp) == 0)
428 return;
429 tty_port_shutdown(port);
Alan Coxd74e8282009-11-30 13:16:52 +0000430 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700431 tty_port_close_end(port, tty);
432 tty_port_tty_set(port, NULL);
433}
434EXPORT_SYMBOL(tty_port_close);
Alan Cox64bc3972009-10-06 16:06:11 +0100435
Jiri Slaby72a33bf2012-08-07 21:47:49 +0200436/**
437 * tty_port_install - generic tty->ops->install handler
438 * @port: tty_port of the device
439 * @driver: tty_driver for this device
440 * @tty: tty to be installed
441 *
442 * It is the same as tty_standard_install except the provided @port is linked
443 * to a concrete tty specified by @tty. Use this or tty_port_register_device
444 * (or both). Call tty_port_link_device as a last resort.
445 */
Jiri Slaby695586c2012-06-04 13:35:32 +0200446int tty_port_install(struct tty_port *port, struct tty_driver *driver,
447 struct tty_struct *tty)
448{
449 tty->port = port;
450 return tty_standard_install(driver, tty);
451}
452EXPORT_SYMBOL_GPL(tty_port_install);
453
Alan Cox64bc3972009-10-06 16:06:11 +0100454int tty_port_open(struct tty_port *port, struct tty_struct *tty,
Alan Coxd774a562009-10-06 16:06:21 +0100455 struct file *filp)
Alan Cox64bc3972009-10-06 16:06:11 +0100456{
457 spin_lock_irq(&port->lock);
458 if (!tty_hung_up_p(filp))
459 ++port->count;
460 spin_unlock_irq(&port->lock);
461 tty_port_tty_set(port, tty);
462
463 /*
464 * Do the device-specific open only if the hardware isn't
465 * already initialized. Serialize open and shutdown using the
466 * port mutex.
467 */
468
469 mutex_lock(&port->mutex);
470
471 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
Alan Coxa9a37ec2009-11-30 13:16:57 +0000472 clear_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox64bc3972009-10-06 16:06:11 +0100473 if (port->ops->activate) {
474 int retval = port->ops->activate(port, tty);
475 if (retval) {
Alan Coxd774a562009-10-06 16:06:21 +0100476 mutex_unlock(&port->mutex);
477 return retval;
478 }
479 }
Alan Cox64bc3972009-10-06 16:06:11 +0100480 set_bit(ASYNCB_INITIALIZED, &port->flags);
481 }
482 mutex_unlock(&port->mutex);
483 return tty_port_block_til_ready(port, tty, filp);
484}
485
486EXPORT_SYMBOL(tty_port_open);