TTY: provide drivers with tty_port_install
[deliverable/linux.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
36int tty_port_alloc_xmit_buf(struct tty_port *port)
37{
38 /* We may sleep in get_zeroed_page() */
44e4909e 39 mutex_lock(&port->buf_mutex);
9e48565d
AC
40 if (port->xmit_buf == NULL)
41 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
44e4909e 42 mutex_unlock(&port->buf_mutex);
9e48565d
AC
43 if (port->xmit_buf == NULL)
44 return -ENOMEM;
45 return 0;
46}
47EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
48
49void tty_port_free_xmit_buf(struct tty_port *port)
50{
44e4909e 51 mutex_lock(&port->buf_mutex);
9e48565d
AC
52 if (port->xmit_buf != NULL) {
53 free_page((unsigned long)port->xmit_buf);
54 port->xmit_buf = NULL;
55 }
44e4909e 56 mutex_unlock(&port->buf_mutex);
9e48565d
AC
57}
58EXPORT_SYMBOL(tty_port_free_xmit_buf);
59
568aafc6
AC
60static void tty_port_destructor(struct kref *kref)
61{
62 struct tty_port *port = container_of(kref, struct tty_port, kref);
63 if (port->xmit_buf)
64 free_page((unsigned long)port->xmit_buf);
65 if (port->ops->destruct)
66 port->ops->destruct(port);
67 else
68 kfree(port);
69}
70
71void tty_port_put(struct tty_port *port)
72{
73 if (port)
74 kref_put(&port->kref, tty_port_destructor);
75}
76EXPORT_SYMBOL(tty_port_put);
9e48565d 77
4a90f09b
AC
78/**
79 * tty_port_tty_get - get a tty reference
80 * @port: tty port
81 *
82 * Return a refcount protected tty instance or NULL if the port is not
83 * associated with a tty (eg due to close or hangup)
84 */
85
86struct tty_struct *tty_port_tty_get(struct tty_port *port)
87{
88 unsigned long flags;
89 struct tty_struct *tty;
90
91 spin_lock_irqsave(&port->lock, flags);
92 tty = tty_kref_get(port->tty);
93 spin_unlock_irqrestore(&port->lock, flags);
94 return tty;
95}
96EXPORT_SYMBOL(tty_port_tty_get);
97
98/**
99 * tty_port_tty_set - set the tty of a port
100 * @port: tty port
101 * @tty: the tty
102 *
103 * Associate the port and tty pair. Manages any internal refcounts.
104 * Pass NULL to deassociate a port
105 */
106
107void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
108{
109 unsigned long flags;
110
111 spin_lock_irqsave(&port->lock, flags);
112 if (port->tty)
113 tty_kref_put(port->tty);
cb4bca35 114 port->tty = tty_kref_get(tty);
4a90f09b
AC
115 spin_unlock_irqrestore(&port->lock, flags);
116}
117EXPORT_SYMBOL(tty_port_tty_set);
31f35939 118
7ca0ff9a
AC
119static void tty_port_shutdown(struct tty_port *port)
120{
64bc3979 121 mutex_lock(&port->mutex);
336cee42 122 if (port->ops->shutdown && !port->console &&
1f5c13fa 123 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
7ca0ff9a 124 port->ops->shutdown(port);
64bc3979 125 mutex_unlock(&port->mutex);
7ca0ff9a
AC
126}
127
3e61696b
AC
128/**
129 * tty_port_hangup - hangup helper
130 * @port: tty port
131 *
132 * Perform port level tty hangup flag and count changes. Drop the tty
133 * reference.
134 */
135
136void tty_port_hangup(struct tty_port *port)
137{
138 unsigned long flags;
139
140 spin_lock_irqsave(&port->lock, flags);
141 port->count = 0;
142 port->flags &= ~ASYNC_NORMAL_ACTIVE;
d74e8286
AC
143 if (port->tty) {
144 set_bit(TTY_IO_ERROR, &port->tty->flags);
3e61696b 145 tty_kref_put(port->tty);
d74e8286 146 }
3e61696b
AC
147 port->tty = NULL;
148 spin_unlock_irqrestore(&port->lock, flags);
149 wake_up_interruptible(&port->open_wait);
bdc04e31 150 wake_up_interruptible(&port->delta_msr_wait);
7ca0ff9a 151 tty_port_shutdown(port);
3e61696b
AC
152}
153EXPORT_SYMBOL(tty_port_hangup);
154
31f35939
AC
155/**
156 * tty_port_carrier_raised - carrier raised check
157 * @port: tty port
158 *
159 * Wrapper for the carrier detect logic. For the moment this is used
160 * to hide some internal details. This will eventually become entirely
161 * internal to the tty port.
162 */
163
164int tty_port_carrier_raised(struct tty_port *port)
165{
166 if (port->ops->carrier_raised == NULL)
167 return 1;
168 return port->ops->carrier_raised(port);
169}
170EXPORT_SYMBOL(tty_port_carrier_raised);
5d951fb4
AC
171
172/**
fcc8ac18 173 * tty_port_raise_dtr_rts - Raise DTR/RTS
5d951fb4
AC
174 * @port: tty port
175 *
176 * Wrapper for the DTR/RTS raise logic. For the moment this is used
177 * to hide some internal details. This will eventually become entirely
178 * internal to the tty port.
179 */
180
181void tty_port_raise_dtr_rts(struct tty_port *port)
182{
fcc8ac18
AC
183 if (port->ops->dtr_rts)
184 port->ops->dtr_rts(port, 1);
5d951fb4
AC
185}
186EXPORT_SYMBOL(tty_port_raise_dtr_rts);
36c621d8 187
fcc8ac18
AC
188/**
189 * tty_port_lower_dtr_rts - Lower DTR/RTS
190 * @port: tty port
191 *
192 * Wrapper for the DTR/RTS raise logic. For the moment this is used
193 * to hide some internal details. This will eventually become entirely
194 * internal to the tty port.
195 */
196
197void tty_port_lower_dtr_rts(struct tty_port *port)
198{
199 if (port->ops->dtr_rts)
200 port->ops->dtr_rts(port, 0);
201}
202EXPORT_SYMBOL(tty_port_lower_dtr_rts);
203
36c621d8
AC
204/**
205 * tty_port_block_til_ready - Waiting logic for tty open
206 * @port: the tty port being opened
207 * @tty: the tty device being bound
208 * @filp: the file pointer of the opener
209 *
210 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
211 * Handles:
212 * - hangup (both before and during)
213 * - non blocking open
214 * - rts/dtr/dcd
215 * - signals
216 * - port flags and counts
217 *
218 * The passed tty_port must implement the carrier_raised method if it can
fcc8ac18 219 * do carrier detect and the dtr_rts method if it supports software
36c621d8
AC
220 * management of these lines. Note that the dtr/rts raise is done each
221 * iteration as a hangup may have previously dropped them while we wait.
222 */
d774a56d 223
36c621d8
AC
224int tty_port_block_til_ready(struct tty_port *port,
225 struct tty_struct *tty, struct file *filp)
226{
227 int do_clocal = 0, retval;
228 unsigned long flags;
6af9a43d 229 DEFINE_WAIT(wait);
36c621d8
AC
230
231 /* block if port is in the process of being closed */
232 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
f309532b 233 wait_event_interruptible_tty(port->close_wait,
5fc5b42a 234 !(port->flags & ASYNC_CLOSING));
36c621d8
AC
235 if (port->flags & ASYNC_HUP_NOTIFY)
236 return -EAGAIN;
237 else
238 return -ERESTARTSYS;
239 }
240
241 /* if non-blocking mode is set we can pass directly to open unless
242 the port has just hung up or is in another error state */
8627b96d
AC
243 if (tty->flags & (1 << TTY_IO_ERROR)) {
244 port->flags |= ASYNC_NORMAL_ACTIVE;
245 return 0;
246 }
247 if (filp->f_flags & O_NONBLOCK) {
4175f3e3
AC
248 /* Indicate we are open */
249 if (tty->termios->c_cflag & CBAUD)
250 tty_port_raise_dtr_rts(port);
36c621d8
AC
251 port->flags |= ASYNC_NORMAL_ACTIVE;
252 return 0;
253 }
254
255 if (C_CLOCAL(tty))
256 do_clocal = 1;
257
258 /* Block waiting until we can proceed. We may need to wait for the
259 carrier, but we must also wait for any close that is in progress
260 before the next open may complete */
261
262 retval = 0;
36c621d8
AC
263
264 /* The port lock protects the port counts */
265 spin_lock_irqsave(&port->lock, flags);
266 if (!tty_hung_up_p(filp))
267 port->count--;
268 port->blocked_open++;
269 spin_unlock_irqrestore(&port->lock, flags);
270
271 while (1) {
272 /* Indicate we are open */
7834909f
AC
273 if (tty->termios->c_cflag & CBAUD)
274 tty_port_raise_dtr_rts(port);
36c621d8 275
3e3b5c08 276 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
d774a56d
AC
277 /* Check for a hangup or uninitialised port.
278 Return accordingly */
36c621d8
AC
279 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
280 if (port->flags & ASYNC_HUP_NOTIFY)
281 retval = -EAGAIN;
282 else
283 retval = -ERESTARTSYS;
284 break;
285 }
0eee50af
JS
286 /*
287 * Probe the carrier. For devices with no carrier detect
288 * tty_port_carrier_raised will always return true.
289 * Never ask drivers if CLOCAL is set, this causes troubles
290 * on some hardware.
291 */
36c621d8 292 if (!(port->flags & ASYNC_CLOSING) &&
0eee50af 293 (do_clocal || tty_port_carrier_raised(port)))
36c621d8
AC
294 break;
295 if (signal_pending(current)) {
296 retval = -ERESTARTSYS;
297 break;
298 }
f309532b 299 tty_unlock();
36c621d8 300 schedule();
f309532b 301 tty_lock();
36c621d8 302 }
3e3b5c08 303 finish_wait(&port->open_wait, &wait);
36c621d8
AC
304
305 /* Update counts. A parallel hangup will have set count to zero and
306 we must not mess that up further */
307 spin_lock_irqsave(&port->lock, flags);
308 if (!tty_hung_up_p(filp))
309 port->count++;
310 port->blocked_open--;
311 if (retval == 0)
312 port->flags |= ASYNC_NORMAL_ACTIVE;
313 spin_unlock_irqrestore(&port->lock, flags);
ecc2e05e 314 return retval;
36c621d8
AC
315}
316EXPORT_SYMBOL(tty_port_block_til_ready);
317
d774a56d
AC
318int tty_port_close_start(struct tty_port *port,
319 struct tty_struct *tty, struct file *filp)
a6614999
AC
320{
321 unsigned long flags;
322
323 spin_lock_irqsave(&port->lock, flags);
324 if (tty_hung_up_p(filp)) {
325 spin_unlock_irqrestore(&port->lock, flags);
326 return 0;
327 }
328
d774a56d 329 if (tty->count == 1 && port->count != 1) {
a6614999
AC
330 printk(KERN_WARNING
331 "tty_port_close_start: tty->count = 1 port count = %d.\n",
332 port->count);
333 port->count = 1;
334 }
335 if (--port->count < 0) {
336 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
337 port->count);
338 port->count = 0;
339 }
340
341 if (port->count) {
342 spin_unlock_irqrestore(&port->lock, flags);
7ca0ff9a
AC
343 if (port->ops->drop)
344 port->ops->drop(port);
a6614999
AC
345 return 0;
346 }
1f5c13fa 347 set_bit(ASYNCB_CLOSING, &port->flags);
a6614999
AC
348 tty->closing = 1;
349 spin_unlock_irqrestore(&port->lock, flags);
fba85e01
AC
350 /* Don't block on a stalled port, just pull the chain */
351 if (tty->flow_stopped)
352 tty_driver_flush_buffer(tty);
7ca0ff9a 353 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
6ed1dbae 354 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
424cc039 355 tty_wait_until_sent_from_close(tty, port->closing_wait);
1ec739be
AC
356 if (port->drain_delay) {
357 unsigned int bps = tty_get_baud_rate(tty);
358 long timeout;
359
360 if (bps > 1200)
d774a56d
AC
361 timeout = max_t(long,
362 (HZ * 10 * port->drain_delay) / bps, HZ / 10);
1ec739be
AC
363 else
364 timeout = 2 * HZ;
365 schedule_timeout_interruptible(timeout);
366 }
e707c35c
AC
367 /* Flush the ldisc buffering */
368 tty_ldisc_flush(tty);
369
370 /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
371 hang up the line */
372 if (tty->termios->c_cflag & HUPCL)
373 tty_port_lower_dtr_rts(port);
374
7ca0ff9a
AC
375 /* Don't call port->drop for the last reference. Callers will want
376 to drop the last active reference in ->shutdown() or the tty
377 shutdown path */
a6614999
AC
378 return 1;
379}
380EXPORT_SYMBOL(tty_port_close_start);
381
382void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
383{
384 unsigned long flags;
385
a6614999
AC
386 spin_lock_irqsave(&port->lock, flags);
387 tty->closing = 0;
388
389 if (port->blocked_open) {
390 spin_unlock_irqrestore(&port->lock, flags);
391 if (port->close_delay) {
392 msleep_interruptible(
393 jiffies_to_msecs(port->close_delay));
394 }
395 spin_lock_irqsave(&port->lock, flags);
396 wake_up_interruptible(&port->open_wait);
397 }
398 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
399 wake_up_interruptible(&port->close_wait);
400 spin_unlock_irqrestore(&port->lock, flags);
401}
402EXPORT_SYMBOL(tty_port_close_end);
7ca0ff9a
AC
403
404void tty_port_close(struct tty_port *port, struct tty_struct *tty,
405 struct file *filp)
406{
407 if (tty_port_close_start(port, tty, filp) == 0)
408 return;
409 tty_port_shutdown(port);
d74e8286 410 set_bit(TTY_IO_ERROR, &tty->flags);
7ca0ff9a
AC
411 tty_port_close_end(port, tty);
412 tty_port_tty_set(port, NULL);
413}
414EXPORT_SYMBOL(tty_port_close);
64bc3979 415
695586ca
JS
416int tty_port_install(struct tty_port *port, struct tty_driver *driver,
417 struct tty_struct *tty)
418{
419 tty->port = port;
420 return tty_standard_install(driver, tty);
421}
422EXPORT_SYMBOL_GPL(tty_port_install);
423
64bc3979 424int tty_port_open(struct tty_port *port, struct tty_struct *tty,
d774a56d 425 struct file *filp)
64bc3979
AC
426{
427 spin_lock_irq(&port->lock);
428 if (!tty_hung_up_p(filp))
429 ++port->count;
430 spin_unlock_irq(&port->lock);
431 tty_port_tty_set(port, tty);
432
433 /*
434 * Do the device-specific open only if the hardware isn't
435 * already initialized. Serialize open and shutdown using the
436 * port mutex.
437 */
438
439 mutex_lock(&port->mutex);
440
441 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
a9a37ec3 442 clear_bit(TTY_IO_ERROR, &tty->flags);
64bc3979
AC
443 if (port->ops->activate) {
444 int retval = port->ops->activate(port, tty);
445 if (retval) {
d774a56d
AC
446 mutex_unlock(&port->mutex);
447 return retval;
448 }
449 }
64bc3979
AC
450 set_bit(ASYNCB_INITIALIZED, &port->flags);
451 }
452 mutex_unlock(&port->mutex);
453 return tty_port_block_til_ready(port, tty, filp);
454}
455
456EXPORT_SYMBOL(tty_port_open);
This page took 0.431348 seconds and 5 git commands to generate.