]> Pileus Git - ~andy/linux/blob - drivers/char/tty_port.c
tty_port: add "tty_port_open" helper
[~andy/linux] / drivers / char / tty_port.c
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>
10 #include <linux/serial.h>
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
21 void 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);
26         init_waitqueue_head(&port->delta_msr_wait);
27         mutex_init(&port->mutex);
28         spin_lock_init(&port->lock);
29         port->close_delay = (50 * HZ) / 100;
30         port->closing_wait = (3000 * HZ) / 100;
31 }
32 EXPORT_SYMBOL(tty_port_init);
33
34 int 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 }
45 EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
46
47 void 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 }
56 EXPORT_SYMBOL(tty_port_free_xmit_buf);
57
58
59 /**
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
67 struct 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 }
77 EXPORT_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
88 void 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);
95         port->tty = tty_kref_get(tty);
96         spin_unlock_irqrestore(&port->lock, flags);
97 }
98 EXPORT_SYMBOL(tty_port_tty_set);
99
100 static void tty_port_shutdown(struct tty_port *port)
101 {
102         mutex_lock(&port->mutex);
103         if (port->ops->shutdown &&
104                 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
105                         port->ops->shutdown(port);
106         mutex_unlock(&port->mutex);
107 }
108
109 /**
110  *      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
117 void 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);
129         wake_up_interruptible(&port->delta_msr_wait);
130         tty_port_shutdown(port);
131 }
132 EXPORT_SYMBOL(tty_port_hangup);
133
134 /**
135  *      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
143 int 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 }
149 EXPORT_SYMBOL(tty_port_carrier_raised);
150
151 /**
152  *      tty_port_raise_dtr_rts  -       Raise DTR/RTS
153  *      @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
160 void tty_port_raise_dtr_rts(struct tty_port *port)
161 {
162         if (port->ops->dtr_rts)
163                 port->ops->dtr_rts(port, 1);
164 }
165 EXPORT_SYMBOL(tty_port_raise_dtr_rts);
166
167 /**
168  *      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
176 void tty_port_lower_dtr_rts(struct tty_port *port)
177 {
178         if (port->ops->dtr_rts)
179                 port->ops->dtr_rts(port, 0);
180 }
181 EXPORT_SYMBOL(tty_port_lower_dtr_rts);
182
183 /**
184  *      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
198  *      do carrier detect and the dtr_rts method if it supports software
199  *      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  */
202  
203 int 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;
208         DEFINE_WAIT(wait);
209         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) {
213                 wait_event_interruptible(port->close_wait,
214                                 !(port->flags & ASYNC_CLOSING));
215                 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 */
223         if (tty->flags & (1 << TTY_IO_ERROR)) {
224                 port->flags |= ASYNC_NORMAL_ACTIVE;
225                 return 0;
226         }
227         if (filp->f_flags & O_NONBLOCK) {
228                 /* Indicate we are open */
229                 if (tty->termios->c_cflag & CBAUD)
230                         tty_port_raise_dtr_rts(port);
231                 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;
243
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 */
253                 if (tty->termios->c_cflag & CBAUD)
254                         tty_port_raise_dtr_rts(port);
255
256                 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
257                 /* Check for a hangup or uninitialised port. Return accordingly */
258                 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
259                         if (port->flags & ASYNC_HUP_NOTIFY)
260                                 retval = -EAGAIN;
261                         else
262                                 retval = -ERESTARTSYS;
263                         break;
264                 }
265                 /* Probe the carrier. For devices with no carrier detect this
266                    will always return true */
267                 cd = tty_port_carrier_raised(port);
268                 if (!(port->flags & ASYNC_CLOSING) &&
269                                 (do_clocal || cd))
270                         break;
271                 if (signal_pending(current)) {
272                         retval = -ERESTARTSYS;
273                         break;
274                 }
275                 schedule();
276         }
277         finish_wait(&port->open_wait, &wait);
278
279         /* Update counts. A parallel hangup will have set count to zero and
280            we must not mess that up further */
281         spin_lock_irqsave(&port->lock, flags);
282         if (!tty_hung_up_p(filp))
283                 port->count++;
284         port->blocked_open--;
285         if (retval == 0)
286                 port->flags |= ASYNC_NORMAL_ACTIVE;
287         spin_unlock_irqrestore(&port->lock, flags);
288         return retval;
289         
290 }
291 EXPORT_SYMBOL(tty_port_block_til_ready);
292
293 int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
294 {
295         unsigned long flags;
296
297         spin_lock_irqsave(&port->lock, flags);
298         if (tty_hung_up_p(filp)) {
299                 spin_unlock_irqrestore(&port->lock, flags);
300                 return 0;
301         }
302
303         if( tty->count == 1 && port->count != 1) {
304                 printk(KERN_WARNING
305                     "tty_port_close_start: tty->count = 1 port count = %d.\n",
306                                                                 port->count);
307                 port->count = 1;
308         }
309         if (--port->count < 0) {
310                 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
311                                                                 port->count);
312                 port->count = 0;
313         }
314
315         if (port->count) {
316                 spin_unlock_irqrestore(&port->lock, flags);
317                 if (port->ops->drop)
318                         port->ops->drop(port);
319                 return 0;
320         }
321         set_bit(ASYNCB_CLOSING, &port->flags);
322         tty->closing = 1;
323         spin_unlock_irqrestore(&port->lock, flags);
324         /* Don't block on a stalled port, just pull the chain */
325         if (tty->flow_stopped)
326                 tty_driver_flush_buffer(tty);
327         if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
328                         port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
329                 tty_wait_until_sent(tty, port->closing_wait);
330         if (port->drain_delay) {
331                 unsigned int bps = tty_get_baud_rate(tty);
332                 long timeout;
333
334                 if (bps > 1200)
335                         timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
336                                                                 HZ / 10);
337                 else
338                         timeout = 2 * HZ;
339                 schedule_timeout_interruptible(timeout);
340         }
341         /* Don't call port->drop for the last reference. Callers will want
342            to drop the last active reference in ->shutdown() or the tty
343            shutdown path */
344         return 1;
345 }
346 EXPORT_SYMBOL(tty_port_close_start);
347
348 void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
349 {
350         unsigned long flags;
351
352         tty_ldisc_flush(tty);
353
354         if (tty->termios->c_cflag & HUPCL)
355                 tty_port_lower_dtr_rts(port);
356
357         spin_lock_irqsave(&port->lock, flags);
358         tty->closing = 0;
359
360         if (port->blocked_open) {
361                 spin_unlock_irqrestore(&port->lock, flags);
362                 if (port->close_delay) {
363                         msleep_interruptible(
364                                 jiffies_to_msecs(port->close_delay));
365                 }
366                 spin_lock_irqsave(&port->lock, flags);
367                 wake_up_interruptible(&port->open_wait);
368         }
369         port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
370         wake_up_interruptible(&port->close_wait);
371         spin_unlock_irqrestore(&port->lock, flags);
372 }
373 EXPORT_SYMBOL(tty_port_close_end);
374
375 void tty_port_close(struct tty_port *port, struct tty_struct *tty,
376                                                         struct file *filp)
377 {
378         if (tty_port_close_start(port, tty, filp) == 0)
379                 return;
380         tty_port_shutdown(port);
381         tty_port_close_end(port, tty);
382         tty_port_tty_set(port, NULL);
383 }
384 EXPORT_SYMBOL(tty_port_close);
385
386 int tty_port_open(struct tty_port *port, struct tty_struct *tty,
387                                                         struct file *filp)
388 {
389         spin_lock_irq(&port->lock);
390         if (!tty_hung_up_p(filp))
391                 ++port->count;
392         spin_unlock_irq(&port->lock);
393         tty_port_tty_set(port, tty);
394
395         /*
396          * Do the device-specific open only if the hardware isn't
397          * already initialized. Serialize open and shutdown using the
398          * port mutex.
399          */
400
401         mutex_lock(&port->mutex);
402
403         if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
404                 if (port->ops->activate) {
405                         int retval = port->ops->activate(port, tty);
406                         if (retval) {
407                                 mutex_unlock(&port->mutex);
408                                 return retval;
409                         }
410                 }
411                 set_bit(ASYNCB_INITIALIZED, &port->flags);
412         }
413         mutex_unlock(&port->mutex);
414         return tty_port_block_til_ready(port, tty, filp);
415 }
416
417 EXPORT_SYMBOL(tty_port_open);