931af10307409dd6a02c99e5a2b32a3aeabbf56d
[pandora-kernel.git] / 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         mutex_init(&port->mutex);
27         spin_lock_init(&port->lock);
28         port->close_delay = (50 * HZ) / 100;
29         port->closing_wait = (3000 * HZ) / 100;
30 }
31 EXPORT_SYMBOL(tty_port_init);
32
33 int tty_port_alloc_xmit_buf(struct tty_port *port)
34 {
35         /* We may sleep in get_zeroed_page() */
36         mutex_lock(&port->mutex);
37         if (port->xmit_buf == NULL)
38                 port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
39         mutex_unlock(&port->mutex);
40         if (port->xmit_buf == NULL)
41                 return -ENOMEM;
42         return 0;
43 }
44 EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
45
46 void tty_port_free_xmit_buf(struct tty_port *port)
47 {
48         mutex_lock(&port->mutex);
49         if (port->xmit_buf != NULL) {
50                 free_page((unsigned long)port->xmit_buf);
51                 port->xmit_buf = NULL;
52         }
53         mutex_unlock(&port->mutex);
54 }
55 EXPORT_SYMBOL(tty_port_free_xmit_buf);
56
57
58 /**
59  *      tty_port_tty_get        -       get a tty reference
60  *      @port: tty port
61  *
62  *      Return a refcount protected tty instance or NULL if the port is not
63  *      associated with a tty (eg due to close or hangup)
64  */
65
66 struct tty_struct *tty_port_tty_get(struct tty_port *port)
67 {
68         unsigned long flags;
69         struct tty_struct *tty;
70
71         spin_lock_irqsave(&port->lock, flags);
72         tty = tty_kref_get(port->tty);
73         spin_unlock_irqrestore(&port->lock, flags);
74         return tty;
75 }
76 EXPORT_SYMBOL(tty_port_tty_get);
77
78 /**
79  *      tty_port_tty_set        -       set the tty of a port
80  *      @port: tty port
81  *      @tty: the tty
82  *
83  *      Associate the port and tty pair. Manages any internal refcounts.
84  *      Pass NULL to deassociate a port
85  */
86
87 void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
88 {
89         unsigned long flags;
90
91         spin_lock_irqsave(&port->lock, flags);
92         if (port->tty)
93                 tty_kref_put(port->tty);
94         port->tty = tty_kref_get(tty);
95         spin_unlock_irqrestore(&port->lock, flags);
96 }
97 EXPORT_SYMBOL(tty_port_tty_set);
98
99 /**
100  *      tty_port_hangup         -       hangup helper
101  *      @port: tty port
102  *
103  *      Perform port level tty hangup flag and count changes. Drop the tty
104  *      reference.
105  */
106
107 void tty_port_hangup(struct tty_port *port)
108 {
109         unsigned long flags;
110
111         spin_lock_irqsave(&port->lock, flags);
112         port->count = 0;
113         port->flags &= ~ASYNC_NORMAL_ACTIVE;
114         if (port->tty)
115                 tty_kref_put(port->tty);
116         port->tty = NULL;
117         spin_unlock_irqrestore(&port->lock, flags);
118         wake_up_interruptible(&port->open_wait);
119 }
120 EXPORT_SYMBOL(tty_port_hangup);
121
122 /**
123  *      tty_port_carrier_raised -       carrier raised check
124  *      @port: tty port
125  *
126  *      Wrapper for the carrier detect logic. For the moment this is used
127  *      to hide some internal details. This will eventually become entirely
128  *      internal to the tty port.
129  */
130
131 int tty_port_carrier_raised(struct tty_port *port)
132 {
133         if (port->ops->carrier_raised == NULL)
134                 return 1;
135         return port->ops->carrier_raised(port);
136 }
137 EXPORT_SYMBOL(tty_port_carrier_raised);
138
139 /**
140  *      tty_port_raise_dtr_rts  -       Raise DTR/RTS
141  *      @port: tty port
142  *
143  *      Wrapper for the DTR/RTS raise logic. For the moment this is used
144  *      to hide some internal details. This will eventually become entirely
145  *      internal to the tty port.
146  */
147
148 void tty_port_raise_dtr_rts(struct tty_port *port)
149 {
150         if (port->ops->dtr_rts)
151                 port->ops->dtr_rts(port, 1);
152 }
153 EXPORT_SYMBOL(tty_port_raise_dtr_rts);
154
155 /**
156  *      tty_port_lower_dtr_rts  -       Lower DTR/RTS
157  *      @port: tty port
158  *
159  *      Wrapper for the DTR/RTS raise 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
164 void tty_port_lower_dtr_rts(struct tty_port *port)
165 {
166         if (port->ops->dtr_rts)
167                 port->ops->dtr_rts(port, 0);
168 }
169 EXPORT_SYMBOL(tty_port_lower_dtr_rts);
170
171 /**
172  *      tty_port_block_til_ready        -       Waiting logic for tty open
173  *      @port: the tty port being opened
174  *      @tty: the tty device being bound
175  *      @filp: the file pointer of the opener
176  *
177  *      Implement the core POSIX/SuS tty behaviour when opening a tty device.
178  *      Handles:
179  *              - hangup (both before and during)
180  *              - non blocking open
181  *              - rts/dtr/dcd
182  *              - signals
183  *              - port flags and counts
184  *
185  *      The passed tty_port must implement the carrier_raised method if it can
186  *      do carrier detect and the dtr_rts method if it supports software
187  *      management of these lines. Note that the dtr/rts raise is done each
188  *      iteration as a hangup may have previously dropped them while we wait.
189  */
190  
191 int tty_port_block_til_ready(struct tty_port *port,
192                                 struct tty_struct *tty, struct file *filp)
193 {
194         int do_clocal = 0, retval;
195         unsigned long flags;
196         DECLARE_WAITQUEUE(wait, current);
197         int cd;
198
199         /* block if port is in the process of being closed */
200         if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
201                 wait_event_interruptible(port->close_wait,
202                                 !(port->flags & ASYNC_CLOSING));
203                 if (port->flags & ASYNC_HUP_NOTIFY)
204                         return -EAGAIN;
205                 else
206                         return -ERESTARTSYS;
207         }
208
209         /* if non-blocking mode is set we can pass directly to open unless
210            the port has just hung up or is in another error state */
211         if ((filp->f_flags & O_NONBLOCK) ||
212                         (tty->flags & (1 << TTY_IO_ERROR))) {
213                 port->flags |= ASYNC_NORMAL_ACTIVE;
214                 return 0;
215         }
216
217         if (C_CLOCAL(tty))
218                 do_clocal = 1;
219
220         /* Block waiting until we can proceed. We may need to wait for the
221            carrier, but we must also wait for any close that is in progress
222            before the next open may complete */
223
224         retval = 0;
225         add_wait_queue(&port->open_wait, &wait);
226
227         /* The port lock protects the port counts */
228         spin_lock_irqsave(&port->lock, flags);
229         if (!tty_hung_up_p(filp))
230                 port->count--;
231         port->blocked_open++;
232         spin_unlock_irqrestore(&port->lock, flags);
233
234         while (1) {
235                 /* Indicate we are open */
236                 if (tty->termios->c_cflag & CBAUD)
237                         tty_port_raise_dtr_rts(port);
238
239                 set_current_state(TASK_INTERRUPTIBLE);
240                 /* Check for a hangup or uninitialised port. Return accordingly */
241                 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
242                         if (port->flags & ASYNC_HUP_NOTIFY)
243                                 retval = -EAGAIN;
244                         else
245                                 retval = -ERESTARTSYS;
246                         break;
247                 }
248                 /* Probe the carrier. For devices with no carrier detect this
249                    will always return true */
250                 cd = tty_port_carrier_raised(port);
251                 if (!(port->flags & ASYNC_CLOSING) &&
252                                 (do_clocal || cd))
253                         break;
254                 if (signal_pending(current)) {
255                         retval = -ERESTARTSYS;
256                         break;
257                 }
258                 schedule();
259         }
260         set_current_state(TASK_RUNNING);
261         remove_wait_queue(&port->open_wait, &wait);
262
263         /* Update counts. A parallel hangup will have set count to zero and
264            we must not mess that up further */
265         spin_lock_irqsave(&port->lock, flags);
266         if (!tty_hung_up_p(filp))
267                 port->count++;
268         port->blocked_open--;
269         if (retval == 0)
270                 port->flags |= ASYNC_NORMAL_ACTIVE;
271         spin_unlock_irqrestore(&port->lock, flags);
272         return 0;
273         
274 }
275 EXPORT_SYMBOL(tty_port_block_til_ready);
276
277 int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
278 {
279         unsigned long flags;
280
281         spin_lock_irqsave(&port->lock, flags);
282         if (tty_hung_up_p(filp)) {
283                 spin_unlock_irqrestore(&port->lock, flags);
284                 return 0;
285         }
286
287         if( tty->count == 1 && port->count != 1) {
288                 printk(KERN_WARNING
289                     "tty_port_close_start: tty->count = 1 port count = %d.\n",
290                                                                 port->count);
291                 port->count = 1;
292         }
293         if (--port->count < 0) {
294                 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
295                                                                 port->count);
296                 port->count = 0;
297         }
298
299         if (port->count) {
300                 spin_unlock_irqrestore(&port->lock, flags);
301                 return 0;
302         }
303         port->flags |= ASYNC_CLOSING;
304         tty->closing = 1;
305         spin_unlock_irqrestore(&port->lock, flags);
306         /* Don't block on a stalled port, just pull the chain */
307         if (tty->flow_stopped)
308                 tty_driver_flush_buffer(tty);
309         if (port->flags & ASYNC_INITIALIZED &&
310                         port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
311                 tty_wait_until_sent(tty, port->closing_wait);
312         if (port->drain_delay) {
313                 unsigned int bps = tty_get_baud_rate(tty);
314                 long timeout;
315
316                 if (bps > 1200)
317                         timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
318                                                                 HZ / 10);
319                 else
320                         timeout = 2 * HZ;
321                 schedule_timeout_interruptible(timeout);
322         }
323         return 1;
324 }
325 EXPORT_SYMBOL(tty_port_close_start);
326
327 void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
328 {
329         unsigned long flags;
330
331         tty_ldisc_flush(tty);
332
333         if (tty->termios->c_cflag & HUPCL)
334                 tty_port_lower_dtr_rts(port);
335
336         spin_lock_irqsave(&port->lock, flags);
337         tty->closing = 0;
338
339         if (port->blocked_open) {
340                 spin_unlock_irqrestore(&port->lock, flags);
341                 if (port->close_delay) {
342                         msleep_interruptible(
343                                 jiffies_to_msecs(port->close_delay));
344                 }
345                 spin_lock_irqsave(&port->lock, flags);
346                 wake_up_interruptible(&port->open_wait);
347         }
348         port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
349         wake_up_interruptible(&port->close_wait);
350         spin_unlock_irqrestore(&port->lock, flags);
351 }
352 EXPORT_SYMBOL(tty_port_close_end);