]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/tty/tty_port.c
tty: handle NULL parameters in free_tty_struct()
[mirror_ubuntu-artful-kernel.git] / drivers / tty / tty_port.c
CommitLineData
9e48565d
AC
1/*
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>
3e61696b 10#include <linux/serial.h>
9e48565d
AC
11#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);
bdc04e31 26 init_waitqueue_head(&port->delta_msr_wait);
9e48565d 27 mutex_init(&port->mutex);
44e4909e 28 mutex_init(&port->buf_mutex);
4a90f09b 29 spin_lock_init(&port->lock);
9e48565d
AC
30 port->close_delay = (50 * HZ) / 100;
31 port->closing_wait = (3000 * HZ) / 100;
568aafc6 32 kref_init(&port->kref);
9e48565d
AC
33}
34EXPORT_SYMBOL(tty_port_init);
35
057eb856
JS
36struct 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
9e48565d
AC
45int tty_port_alloc_xmit_buf(struct tty_port *port)
46{
47 /* We may sleep in get_zeroed_page() */
44e4909e 48 mutex_lock(&port->buf_mutex);
9e48565d
AC
49 if (port->xmit_buf == NULL)
50 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
44e4909e 51 mutex_unlock(&port->buf_mutex);
9e48565d
AC
52 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{
44e4909e 60 mutex_lock(&port->buf_mutex);
9e48565d
AC
61 if (port->xmit_buf != NULL) {
62 free_page((unsigned long)port->xmit_buf);
63 port->xmit_buf = NULL;
64 }
44e4909e 65 mutex_unlock(&port->buf_mutex);
9e48565d
AC
66}
67EXPORT_SYMBOL(tty_port_free_xmit_buf);
68
568aafc6
AC
69static 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);
9e48565d 86
4a90f09b
AC
87/**
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);
cb4bca35 123 port->tty = tty_kref_get(tty);
4a90f09b
AC
124 spin_unlock_irqrestore(&port->lock, flags);
125}
126EXPORT_SYMBOL(tty_port_tty_set);
31f35939 127
7ca0ff9a
AC
128static void tty_port_shutdown(struct tty_port *port)
129{
64bc3979 130 mutex_lock(&port->mutex);
336cee42 131 if (port->ops->shutdown && !port->console &&
1f5c13fa 132 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
7ca0ff9a 133 port->ops->shutdown(port);
64bc3979 134 mutex_unlock(&port->mutex);
7ca0ff9a
AC
135}
136
3e61696b
AC
137/**
138 * 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;
d74e8286
AC
152 if (port->tty) {
153 set_bit(TTY_IO_ERROR, &port->tty->flags);
3e61696b 154 tty_kref_put(port->tty);
d74e8286 155 }
3e61696b
AC
156 port->tty = NULL;
157 spin_unlock_irqrestore(&port->lock, flags);
158 wake_up_interruptible(&port->open_wait);
bdc04e31 159 wake_up_interruptible(&port->delta_msr_wait);
7ca0ff9a 160 tty_port_shutdown(port);
3e61696b
AC
161}
162EXPORT_SYMBOL(tty_port_hangup);
163
31f35939
AC
164/**
165 * 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);
5d951fb4
AC
180
181/**
fcc8ac18 182 * tty_port_raise_dtr_rts - Raise DTR/RTS
5d951fb4
AC
183 * @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{
fcc8ac18
AC
192 if (port->ops->dtr_rts)
193 port->ops->dtr_rts(port, 1);
5d951fb4
AC
194}
195EXPORT_SYMBOL(tty_port_raise_dtr_rts);
36c621d8 196
fcc8ac18
AC
197/**
198 * 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
36c621d8
AC
213/**
214 * 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
fcc8ac18 228 * do carrier detect and the dtr_rts method if it supports software
36c621d8
AC
229 * 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 */
d774a56d 232
36c621d8
AC
233int 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;
6af9a43d 238 DEFINE_WAIT(wait);
36c621d8
AC
239
240 /* block if port is in the process of being closed */
241 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
6d31a88c 242 wait_event_interruptible_tty(port->close_wait,
5fc5b42a 243 !(port->flags & ASYNC_CLOSING));
36c621d8
AC
244 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 */
8627b96d
AC
252 if (tty->flags & (1 << TTY_IO_ERROR)) {
253 port->flags |= ASYNC_NORMAL_ACTIVE;
254 return 0;
255 }
256 if (filp->f_flags & O_NONBLOCK) {
4175f3e3 257 /* Indicate we are open */
adc8d746 258 if (tty->termios.c_cflag & CBAUD)
4175f3e3 259 tty_port_raise_dtr_rts(port);
36c621d8
AC
260 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;
36c621d8
AC
272
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 */
adc8d746 282 if (tty->termios.c_cflag & CBAUD)
7834909f 283 tty_port_raise_dtr_rts(port);
36c621d8 284
3e3b5c08 285 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
d774a56d
AC
286 /* Check for a hangup or uninitialised port.
287 Return accordingly */
36c621d8
AC
288 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 }
0eee50af
JS
295 /*
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 */
36c621d8 301 if (!(port->flags & ASYNC_CLOSING) &&
0eee50af 302 (do_clocal || tty_port_carrier_raised(port)))
36c621d8
AC
303 break;
304 if (signal_pending(current)) {
305 retval = -ERESTARTSYS;
306 break;
307 }
6d31a88c 308 tty_unlock();
36c621d8 309 schedule();
6d31a88c 310 tty_lock();
36c621d8 311 }
3e3b5c08 312 finish_wait(&port->open_wait, &wait);
36c621d8
AC
313
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);
ecc2e05e 323 return retval;
36c621d8
AC
324}
325EXPORT_SYMBOL(tty_port_block_til_ready);
326
d774a56d
AC
327int tty_port_close_start(struct tty_port *port,
328 struct tty_struct *tty, struct file *filp)
a6614999
AC
329{
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
d774a56d 338 if (tty->count == 1 && port->count != 1) {
a6614999
AC
339 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);
7ca0ff9a
AC
352 if (port->ops->drop)
353 port->ops->drop(port);
a6614999
AC
354 return 0;
355 }
1f5c13fa 356 set_bit(ASYNCB_CLOSING, &port->flags);
a6614999
AC
357 tty->closing = 1;
358 spin_unlock_irqrestore(&port->lock, flags);
fba85e01
AC
359 /* Don't block on a stalled port, just pull the chain */
360 if (tty->flow_stopped)
361 tty_driver_flush_buffer(tty);
7ca0ff9a 362 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
6ed1dbae 363 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
424cc039 364 tty_wait_until_sent_from_close(tty, port->closing_wait);
1ec739be
AC
365 if (port->drain_delay) {
366 unsigned int bps = tty_get_baud_rate(tty);
367 long timeout;
368
369 if (bps > 1200)
d774a56d
AC
370 timeout = max_t(long,
371 (HZ * 10 * port->drain_delay) / bps, HZ / 10);
1ec739be
AC
372 else
373 timeout = 2 * HZ;
374 schedule_timeout_interruptible(timeout);
375 }
e707c35c
AC
376 /* 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 */
adc8d746 381 if (tty->termios.c_cflag & HUPCL)
e707c35c
AC
382 tty_port_lower_dtr_rts(port);
383
7ca0ff9a
AC
384 /* 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 */
a6614999
AC
387 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
a6614999
AC
395 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);
7ca0ff9a
AC
412
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);
d74e8286 419 set_bit(TTY_IO_ERROR, &tty->flags);
7ca0ff9a
AC
420 tty_port_close_end(port, tty);
421 tty_port_tty_set(port, NULL);
422}
423EXPORT_SYMBOL(tty_port_close);
64bc3979 424
695586ca
JS
425int 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
64bc3979 433int tty_port_open(struct tty_port *port, struct tty_struct *tty,
d774a56d 434 struct file *filp)
64bc3979
AC
435{
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)) {
a9a37ec3 451 clear_bit(TTY_IO_ERROR, &tty->flags);
64bc3979
AC
452 if (port->ops->activate) {
453 int retval = port->ops->activate(port, tty);
454 if (retval) {
d774a56d
AC
455 mutex_unlock(&port->mutex);
456 return retval;
457 }
458 }
64bc3979
AC
459 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);