blob: dd471d63fae2c2673cc40cfb9235ac88828fdcce [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 */
Alan Coxd774a562009-10-06 16:06:21 +0100202
Alan Cox36c621d2009-01-02 13:46:10 +0000203int 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 Coxd774a562009-10-06 16:06:21 +0100257 /* Check for a hangup or uninitialised port.
258 Return accordingly */
Alan Cox36c621d2009-01-02 13:46:10 +0000259 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
260 if (port->flags & ASYNC_HUP_NOTIFY)
261 retval = -EAGAIN;
262 else
263 retval = -ERESTARTSYS;
264 break;
265 }
266 /* Probe the carrier. For devices with no carrier detect this
267 will always return true */
268 cd = tty_port_carrier_raised(port);
269 if (!(port->flags & ASYNC_CLOSING) &&
270 (do_clocal || cd))
271 break;
272 if (signal_pending(current)) {
273 retval = -ERESTARTSYS;
274 break;
275 }
276 schedule();
277 }
Jiri Slaby3e3b5c02009-06-11 14:33:37 +0100278 finish_wait(&port->open_wait, &wait);
Alan Cox36c621d2009-01-02 13:46:10 +0000279
280 /* Update counts. A parallel hangup will have set count to zero and
281 we must not mess that up further */
282 spin_lock_irqsave(&port->lock, flags);
283 if (!tty_hung_up_p(filp))
284 port->count++;
285 port->blocked_open--;
286 if (retval == 0)
287 port->flags |= ASYNC_NORMAL_ACTIVE;
288 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxecc2e052009-07-17 16:17:26 +0100289 return retval;
Alan Cox36c621d2009-01-02 13:46:10 +0000290}
291EXPORT_SYMBOL(tty_port_block_til_ready);
292
Alan Coxd774a562009-10-06 16:06:21 +0100293int tty_port_close_start(struct tty_port *port,
294 struct tty_struct *tty, struct file *filp)
Alan Coxa6614992009-01-02 13:46:50 +0000295{
296 unsigned long flags;
297
298 spin_lock_irqsave(&port->lock, flags);
299 if (tty_hung_up_p(filp)) {
300 spin_unlock_irqrestore(&port->lock, flags);
301 return 0;
302 }
303
Alan Coxd774a562009-10-06 16:06:21 +0100304 if (tty->count == 1 && port->count != 1) {
Alan Coxa6614992009-01-02 13:46:50 +0000305 printk(KERN_WARNING
306 "tty_port_close_start: tty->count = 1 port count = %d.\n",
307 port->count);
308 port->count = 1;
309 }
310 if (--port->count < 0) {
311 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
312 port->count);
313 port->count = 0;
314 }
315
316 if (port->count) {
317 spin_unlock_irqrestore(&port->lock, flags);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700318 if (port->ops->drop)
319 port->ops->drop(port);
Alan Coxa6614992009-01-02 13:46:50 +0000320 return 0;
321 }
Alan Stern1f5c13f2009-08-20 15:23:47 -0400322 set_bit(ASYNCB_CLOSING, &port->flags);
Alan Coxa6614992009-01-02 13:46:50 +0000323 tty->closing = 1;
324 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxfba85e02009-01-02 13:48:39 +0000325 /* Don't block on a stalled port, just pull the chain */
326 if (tty->flow_stopped)
327 tty_driver_flush_buffer(tty);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700328 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
Alan Cox6ed1dba2009-01-02 13:48:11 +0000329 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
Alan Coxa6614992009-01-02 13:46:50 +0000330 tty_wait_until_sent(tty, port->closing_wait);
Alan Cox1ec739b2009-06-11 12:25:25 +0100331 if (port->drain_delay) {
332 unsigned int bps = tty_get_baud_rate(tty);
333 long timeout;
334
335 if (bps > 1200)
Alan Coxd774a562009-10-06 16:06:21 +0100336 timeout = max_t(long,
337 (HZ * 10 * port->drain_delay) / bps, HZ / 10);
Alan Cox1ec739b2009-06-11 12:25:25 +0100338 else
339 timeout = 2 * HZ;
340 schedule_timeout_interruptible(timeout);
341 }
Alan Coxe707c352009-11-05 13:27:57 +0000342 /* Flush the ldisc buffering */
343 tty_ldisc_flush(tty);
344
345 /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
346 hang up the line */
347 if (tty->termios->c_cflag & HUPCL)
348 tty_port_lower_dtr_rts(port);
349
Alan Cox7ca0ff92009-09-19 13:13:20 -0700350 /* Don't call port->drop for the last reference. Callers will want
351 to drop the last active reference in ->shutdown() or the tty
352 shutdown path */
Alan Coxa6614992009-01-02 13:46:50 +0000353 return 1;
354}
355EXPORT_SYMBOL(tty_port_close_start);
356
357void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
358{
359 unsigned long flags;
360
Alan Coxa6614992009-01-02 13:46:50 +0000361 spin_lock_irqsave(&port->lock, flags);
362 tty->closing = 0;
363
364 if (port->blocked_open) {
365 spin_unlock_irqrestore(&port->lock, flags);
366 if (port->close_delay) {
367 msleep_interruptible(
368 jiffies_to_msecs(port->close_delay));
369 }
370 spin_lock_irqsave(&port->lock, flags);
371 wake_up_interruptible(&port->open_wait);
372 }
373 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
374 wake_up_interruptible(&port->close_wait);
375 spin_unlock_irqrestore(&port->lock, flags);
376}
377EXPORT_SYMBOL(tty_port_close_end);
Alan Cox7ca0ff92009-09-19 13:13:20 -0700378
379void tty_port_close(struct tty_port *port, struct tty_struct *tty,
380 struct file *filp)
381{
382 if (tty_port_close_start(port, tty, filp) == 0)
383 return;
384 tty_port_shutdown(port);
385 tty_port_close_end(port, tty);
386 tty_port_tty_set(port, NULL);
387}
388EXPORT_SYMBOL(tty_port_close);
Alan Cox64bc3972009-10-06 16:06:11 +0100389
390int tty_port_open(struct tty_port *port, struct tty_struct *tty,
Alan Coxd774a562009-10-06 16:06:21 +0100391 struct file *filp)
Alan Cox64bc3972009-10-06 16:06:11 +0100392{
393 spin_lock_irq(&port->lock);
394 if (!tty_hung_up_p(filp))
395 ++port->count;
396 spin_unlock_irq(&port->lock);
397 tty_port_tty_set(port, tty);
398
399 /*
400 * Do the device-specific open only if the hardware isn't
401 * already initialized. Serialize open and shutdown using the
402 * port mutex.
403 */
404
405 mutex_lock(&port->mutex);
406
407 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
408 if (port->ops->activate) {
409 int retval = port->ops->activate(port, tty);
410 if (retval) {
Alan Coxd774a562009-10-06 16:06:21 +0100411 mutex_unlock(&port->mutex);
412 return retval;
413 }
414 }
Alan Cox64bc3972009-10-06 16:06:11 +0100415 set_bit(ASYNCB_INITIALIZED, &port->flags);
416 }
417 mutex_unlock(&port->mutex);
418 return tty_port_block_til_ready(port, tty, filp);
419}
420
421EXPORT_SYMBOL(tty_port_open);