blob: 3ef644a2e517c66e9671039e989485f6c395c1ea [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;
32}
33EXPORT_SYMBOL(tty_port_init);
34
35int tty_port_alloc_xmit_buf(struct tty_port *port)
36{
37 /* We may sleep in get_zeroed_page() */
Alan Cox44e49092009-11-30 13:16:41 +000038 mutex_lock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010039 if (port->xmit_buf == NULL)
40 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
Alan Cox44e49092009-11-30 13:16:41 +000041 mutex_unlock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010042 if (port->xmit_buf == NULL)
43 return -ENOMEM;
44 return 0;
45}
46EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
47
48void tty_port_free_xmit_buf(struct tty_port *port)
49{
Alan Cox44e49092009-11-30 13:16:41 +000050 mutex_lock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010051 if (port->xmit_buf != NULL) {
52 free_page((unsigned long)port->xmit_buf);
53 port->xmit_buf = NULL;
54 }
Alan Cox44e49092009-11-30 13:16:41 +000055 mutex_unlock(&port->buf_mutex);
Alan Cox9e485652008-10-13 10:37:07 +010056}
57EXPORT_SYMBOL(tty_port_free_xmit_buf);
58
59
Alan Cox4a90f092008-10-13 10:39:46 +010060/**
61 * tty_port_tty_get - get a tty reference
62 * @port: tty port
63 *
64 * Return a refcount protected tty instance or NULL if the port is not
65 * associated with a tty (eg due to close or hangup)
66 */
67
68struct tty_struct *tty_port_tty_get(struct tty_port *port)
69{
70 unsigned long flags;
71 struct tty_struct *tty;
72
73 spin_lock_irqsave(&port->lock, flags);
74 tty = tty_kref_get(port->tty);
75 spin_unlock_irqrestore(&port->lock, flags);
76 return tty;
77}
78EXPORT_SYMBOL(tty_port_tty_get);
79
80/**
81 * tty_port_tty_set - set the tty of a port
82 * @port: tty port
83 * @tty: the tty
84 *
85 * Associate the port and tty pair. Manages any internal refcounts.
86 * Pass NULL to deassociate a port
87 */
88
89void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
90{
91 unsigned long flags;
92
93 spin_lock_irqsave(&port->lock, flags);
94 if (port->tty)
95 tty_kref_put(port->tty);
Alan Coxcb4bca32008-10-21 13:47:44 +010096 port->tty = tty_kref_get(tty);
Alan Cox4a90f092008-10-13 10:39:46 +010097 spin_unlock_irqrestore(&port->lock, flags);
98}
99EXPORT_SYMBOL(tty_port_tty_set);
Alan Cox31f35932009-01-02 13:45:05 +0000100
Alan Cox7ca0ff92009-09-19 13:13:20 -0700101static void tty_port_shutdown(struct tty_port *port)
102{
Alan Cox64bc3972009-10-06 16:06:11 +0100103 mutex_lock(&port->mutex);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700104 if (port->ops->shutdown &&
Alan Stern1f5c13f2009-08-20 15:23:47 -0400105 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
Alan Cox7ca0ff92009-09-19 13:13:20 -0700106 port->ops->shutdown(port);
Alan Cox64bc3972009-10-06 16:06:11 +0100107 mutex_unlock(&port->mutex);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700108}
109
Alan Cox31f35932009-01-02 13:45:05 +0000110/**
Alan Cox3e616962009-01-02 13:45:26 +0000111 * tty_port_hangup - hangup helper
112 * @port: tty port
113 *
114 * Perform port level tty hangup flag and count changes. Drop the tty
115 * reference.
116 */
117
118void tty_port_hangup(struct tty_port *port)
119{
120 unsigned long flags;
121
122 spin_lock_irqsave(&port->lock, flags);
123 port->count = 0;
124 port->flags &= ~ASYNC_NORMAL_ACTIVE;
125 if (port->tty)
126 tty_kref_put(port->tty);
127 port->tty = NULL;
128 spin_unlock_irqrestore(&port->lock, flags);
129 wake_up_interruptible(&port->open_wait);
Alan Coxbdc04e32009-09-19 13:13:31 -0700130 wake_up_interruptible(&port->delta_msr_wait);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700131 tty_port_shutdown(port);
Alan Cox3e616962009-01-02 13:45:26 +0000132}
133EXPORT_SYMBOL(tty_port_hangup);
134
135/**
Alan Cox31f35932009-01-02 13:45:05 +0000136 * tty_port_carrier_raised - carrier raised check
137 * @port: tty port
138 *
139 * Wrapper for the carrier detect logic. For the moment this is used
140 * to hide some internal details. This will eventually become entirely
141 * internal to the tty port.
142 */
143
144int tty_port_carrier_raised(struct tty_port *port)
145{
146 if (port->ops->carrier_raised == NULL)
147 return 1;
148 return port->ops->carrier_raised(port);
149}
150EXPORT_SYMBOL(tty_port_carrier_raised);
Alan Cox5d951fb2009-01-02 13:45:19 +0000151
152/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100153 * tty_port_raise_dtr_rts - Raise DTR/RTS
Alan Cox5d951fb2009-01-02 13:45:19 +0000154 * @port: tty port
155 *
156 * Wrapper for the DTR/RTS raise logic. For the moment this is used
157 * to hide some internal details. This will eventually become entirely
158 * internal to the tty port.
159 */
160
161void tty_port_raise_dtr_rts(struct tty_port *port)
162{
Alan Coxfcc8ac12009-06-11 12:24:17 +0100163 if (port->ops->dtr_rts)
164 port->ops->dtr_rts(port, 1);
Alan Cox5d951fb2009-01-02 13:45:19 +0000165}
166EXPORT_SYMBOL(tty_port_raise_dtr_rts);
Alan Cox36c621d2009-01-02 13:46:10 +0000167
168/**
Alan Coxfcc8ac12009-06-11 12:24:17 +0100169 * tty_port_lower_dtr_rts - Lower DTR/RTS
170 * @port: tty port
171 *
172 * Wrapper for the DTR/RTS raise logic. For the moment this is used
173 * to hide some internal details. This will eventually become entirely
174 * internal to the tty port.
175 */
176
177void tty_port_lower_dtr_rts(struct tty_port *port)
178{
179 if (port->ops->dtr_rts)
180 port->ops->dtr_rts(port, 0);
181}
182EXPORT_SYMBOL(tty_port_lower_dtr_rts);
183
184/**
Alan Cox36c621d2009-01-02 13:46:10 +0000185 * tty_port_block_til_ready - Waiting logic for tty open
186 * @port: the tty port being opened
187 * @tty: the tty device being bound
188 * @filp: the file pointer of the opener
189 *
190 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
191 * Handles:
192 * - hangup (both before and during)
193 * - non blocking open
194 * - rts/dtr/dcd
195 * - signals
196 * - port flags and counts
197 *
198 * The passed tty_port must implement the carrier_raised method if it can
Alan Coxfcc8ac12009-06-11 12:24:17 +0100199 * do carrier detect and the dtr_rts method if it supports software
Alan Cox36c621d2009-01-02 13:46:10 +0000200 * management of these lines. Note that the dtr/rts raise is done each
201 * iteration as a hangup may have previously dropped them while we wait.
202 */
Alan Coxd774a562009-10-06 16:06:21 +0100203
Alan Cox36c621d2009-01-02 13:46:10 +0000204int tty_port_block_til_ready(struct tty_port *port,
205 struct tty_struct *tty, struct file *filp)
206{
207 int do_clocal = 0, retval;
208 unsigned long flags;
Jiri Slaby6af9a432009-06-24 18:35:05 +0100209 DEFINE_WAIT(wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000210 int cd;
211
212 /* block if port is in the process of being closed */
213 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
Jiri Slaby5fc5b422009-06-11 14:32:42 +0100214 wait_event_interruptible(port->close_wait,
215 !(port->flags & ASYNC_CLOSING));
Alan Cox36c621d2009-01-02 13:46:10 +0000216 if (port->flags & ASYNC_HUP_NOTIFY)
217 return -EAGAIN;
218 else
219 return -ERESTARTSYS;
220 }
221
222 /* if non-blocking mode is set we can pass directly to open unless
223 the port has just hung up or is in another error state */
Alan Cox8627b962009-11-18 14:12:58 +0000224 if (tty->flags & (1 << TTY_IO_ERROR)) {
225 port->flags |= ASYNC_NORMAL_ACTIVE;
226 return 0;
227 }
228 if (filp->f_flags & O_NONBLOCK) {
Alan Cox4175f3e2009-10-28 21:12:32 +0100229 /* Indicate we are open */
230 if (tty->termios->c_cflag & CBAUD)
231 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000232 port->flags |= ASYNC_NORMAL_ACTIVE;
233 return 0;
234 }
235
236 if (C_CLOCAL(tty))
237 do_clocal = 1;
238
239 /* Block waiting until we can proceed. We may need to wait for the
240 carrier, but we must also wait for any close that is in progress
241 before the next open may complete */
242
243 retval = 0;
Alan Cox36c621d2009-01-02 13:46:10 +0000244
245 /* The port lock protects the port counts */
246 spin_lock_irqsave(&port->lock, flags);
247 if (!tty_hung_up_p(filp))
248 port->count--;
249 port->blocked_open++;
250 spin_unlock_irqrestore(&port->lock, flags);
251
252 while (1) {
253 /* Indicate we are open */
Alan Cox78349092009-01-02 13:46:43 +0000254 if (tty->termios->c_cflag & CBAUD)
255 tty_port_raise_dtr_rts(port);
Alan Cox36c621d2009-01-02 13:46:10 +0000256
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100257 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
Alan Coxd774a562009-10-06 16:06:21 +0100258 /* Check for a hangup or uninitialised port.
259 Return accordingly */
Alan Cox36c621d2009-01-02 13:46:10 +0000260 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
261 if (port->flags & ASYNC_HUP_NOTIFY)
262 retval = -EAGAIN;
263 else
264 retval = -ERESTARTSYS;
265 break;
266 }
267 /* Probe the carrier. For devices with no carrier detect this
268 will always return true */
269 cd = tty_port_carrier_raised(port);
270 if (!(port->flags & ASYNC_CLOSING) &&
271 (do_clocal || cd))
272 break;
273 if (signal_pending(current)) {
274 retval = -ERESTARTSYS;
275 break;
276 }
277 schedule();
278 }
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100279 finish_wait(&port->open_wait, &wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000280
281 /* Update counts. A parallel hangup will have set count to zero and
282 we must not mess that up further */
283 spin_lock_irqsave(&port->lock, flags);
284 if (!tty_hung_up_p(filp))
285 port->count++;
286 port->blocked_open--;
287 if (retval == 0)
288 port->flags |= ASYNC_NORMAL_ACTIVE;
289 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxecc2e052009-07-17 16:17:26 +0100290 return retval;
Alan Cox36c621d2009-01-02 13:46:10 +0000291}
292EXPORT_SYMBOL(tty_port_block_til_ready);
293
Alan Coxd774a562009-10-06 16:06:21 +0100294int tty_port_close_start(struct tty_port *port,
295 struct tty_struct *tty, struct file *filp)
Alan Coxa6614992009-01-02 13:46:50 +0000296{
297 unsigned long flags;
298
299 spin_lock_irqsave(&port->lock, flags);
300 if (tty_hung_up_p(filp)) {
301 spin_unlock_irqrestore(&port->lock, flags);
302 return 0;
303 }
304
Alan Coxd774a562009-10-06 16:06:21 +0100305 if (tty->count == 1 && port->count != 1) {
Alan Coxa6614992009-01-02 13:46:50 +0000306 printk(KERN_WARNING
307 "tty_port_close_start: tty->count = 1 port count = %d.\n",
308 port->count);
309 port->count = 1;
310 }
311 if (--port->count < 0) {
312 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
313 port->count);
314 port->count = 0;
315 }
316
317 if (port->count) {
318 spin_unlock_irqrestore(&port->lock, flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700319 if (port->ops->drop)
320 port->ops->drop(port);
Alan Coxa6614992009-01-02 13:46:50 +0000321 return 0;
322 }
Alan Stern1f5c13f2009-08-20 15:23:47 -0400323 set_bit(ASYNCB_CLOSING, &port->flags);
Alan Coxa6614992009-01-02 13:46:50 +0000324 tty->closing = 1;
325 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxfba85e02009-01-02 13:48:39 +0000326 /* Don't block on a stalled port, just pull the chain */
327 if (tty->flow_stopped)
328 tty_driver_flush_buffer(tty);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700329 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
Alan Cox6ed1dba2009-01-02 13:48:11 +0000330 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Alan Coxa6614992009-01-02 13:46:50 +0000331 tty_wait_until_sent(tty, port->closing_wait);
Alan Cox1ec739b2009-06-11 12:25:25 +0100332 if (port->drain_delay) {
333 unsigned int bps = tty_get_baud_rate(tty);
334 long timeout;
335
336 if (bps > 1200)
Alan Coxd774a562009-10-06 16:06:21 +0100337 timeout = max_t(long,
338 (HZ * 10 * port->drain_delay) / bps, HZ / 10);
Alan Cox1ec739b2009-06-11 12:25:25 +0100339 else
340 timeout = 2 * HZ;
341 schedule_timeout_interruptible(timeout);
342 }
Alan Coxe707c352009-11-05 13:27:57 +0000343 /* Flush the ldisc buffering */
344 tty_ldisc_flush(tty);
345
346 /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
347 hang up the line */
348 if (tty->termios->c_cflag & HUPCL)
349 tty_port_lower_dtr_rts(port);
350
Alan Cox7ca0ff92009-09-19 13:13:20 -0700351 /* Don't call port->drop for the last reference. Callers will want
352 to drop the last active reference in ->shutdown() or the tty
353 shutdown path */
Alan Coxa6614992009-01-02 13:46:50 +0000354 return 1;
355}
356EXPORT_SYMBOL(tty_port_close_start);
357
358void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
359{
360 unsigned long flags;
361
Alan Coxa6614992009-01-02 13:46:50 +0000362 spin_lock_irqsave(&port->lock, flags);
363 tty->closing = 0;
364
365 if (port->blocked_open) {
366 spin_unlock_irqrestore(&port->lock, flags);
367 if (port->close_delay) {
368 msleep_interruptible(
369 jiffies_to_msecs(port->close_delay));
370 }
371 spin_lock_irqsave(&port->lock, flags);
372 wake_up_interruptible(&port->open_wait);
373 }
374 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
375 wake_up_interruptible(&port->close_wait);
376 spin_unlock_irqrestore(&port->lock, flags);
377}
378EXPORT_SYMBOL(tty_port_close_end);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700379
380void tty_port_close(struct tty_port *port, struct tty_struct *tty,
381 struct file *filp)
382{
383 if (tty_port_close_start(port, tty, filp) == 0)
384 return;
385 tty_port_shutdown(port);
386 tty_port_close_end(port, tty);
387 tty_port_tty_set(port, NULL);
388}
389EXPORT_SYMBOL(tty_port_close);
Alan Cox64bc3972009-10-06 16:06:11 +0100390
391int tty_port_open(struct tty_port *port, struct tty_struct *tty,
Alan Coxd774a562009-10-06 16:06:21 +0100392 struct file *filp)
Alan Cox64bc3972009-10-06 16:06:11 +0100393{
394 spin_lock_irq(&port->lock);
395 if (!tty_hung_up_p(filp))
396 ++port->count;
397 spin_unlock_irq(&port->lock);
398 tty_port_tty_set(port, tty);
399
400 /*
401 * Do the device-specific open only if the hardware isn't
402 * already initialized. Serialize open and shutdown using the
403 * port mutex.
404 */
405
406 mutex_lock(&port->mutex);
407
408 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
409 if (port->ops->activate) {
410 int retval = port->ops->activate(port, tty);
411 if (retval) {
Alan Coxd774a562009-10-06 16:06:21 +0100412 mutex_unlock(&port->mutex);
413 return retval;
414 }
415 }
Alan Cox64bc3972009-10-06 16:06:11 +0100416 set_bit(ASYNCB_INITIALIZED, &port->flags);
417 }
418 mutex_unlock(&port->mutex);
419 return tty_port_block_til_ready(port, tty, filp);
420}
421
422EXPORT_SYMBOL(tty_port_open);