tty: use port methods for the rocket driver
[deliverable/linux.git] / drivers / char / 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);
26 mutex_init(&port->mutex);
4a90f09b 27 spin_lock_init(&port->lock);
9e48565d
AC
28 port->close_delay = (50 * HZ) / 100;
29 port->closing_wait = (3000 * HZ) / 100;
30}
31EXPORT_SYMBOL(tty_port_init);
32
33int 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}
44EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
45
46void 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}
55EXPORT_SYMBOL(tty_port_free_xmit_buf);
56
57
4a90f09b
AC
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
66struct 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}
76EXPORT_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
87void 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);
cb4bca35 94 port->tty = tty_kref_get(tty);
4a90f09b
AC
95 spin_unlock_irqrestore(&port->lock, flags);
96}
97EXPORT_SYMBOL(tty_port_tty_set);
31f35939 98
3e61696b
AC
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
107void 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}
120EXPORT_SYMBOL(tty_port_hangup);
121
31f35939
AC
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
131int 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}
137EXPORT_SYMBOL(tty_port_carrier_raised);
5d951fb4
AC
138
139/**
140 * tty_port_raise_dtr_rts - Riase 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
148void tty_port_raise_dtr_rts(struct tty_port *port)
149{
150 if (port->ops->raise_dtr_rts)
151 port->ops->raise_dtr_rts(port);
152}
153EXPORT_SYMBOL(tty_port_raise_dtr_rts);
36c621d8
AC
154
155/**
156 * tty_port_block_til_ready - Waiting logic for tty open
157 * @port: the tty port being opened
158 * @tty: the tty device being bound
159 * @filp: the file pointer of the opener
160 *
161 * Implement the core POSIX/SuS tty behaviour when opening a tty device.
162 * Handles:
163 * - hangup (both before and during)
164 * - non blocking open
165 * - rts/dtr/dcd
166 * - signals
167 * - port flags and counts
168 *
169 * The passed tty_port must implement the carrier_raised method if it can
170 * do carrier detect and the raise_dtr_rts method if it supports software
171 * management of these lines. Note that the dtr/rts raise is done each
172 * iteration as a hangup may have previously dropped them while we wait.
173 */
174
175int tty_port_block_til_ready(struct tty_port *port,
176 struct tty_struct *tty, struct file *filp)
177{
178 int do_clocal = 0, retval;
179 unsigned long flags;
180 DECLARE_WAITQUEUE(wait, current);
181 int cd;
182
183 /* block if port is in the process of being closed */
184 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
185 interruptible_sleep_on(&port->close_wait);
186 if (port->flags & ASYNC_HUP_NOTIFY)
187 return -EAGAIN;
188 else
189 return -ERESTARTSYS;
190 }
191
192 /* if non-blocking mode is set we can pass directly to open unless
193 the port has just hung up or is in another error state */
194 if ((filp->f_flags & O_NONBLOCK) ||
195 (tty->flags & (1 << TTY_IO_ERROR))) {
196 port->flags |= ASYNC_NORMAL_ACTIVE;
197 return 0;
198 }
199
200 if (C_CLOCAL(tty))
201 do_clocal = 1;
202
203 /* Block waiting until we can proceed. We may need to wait for the
204 carrier, but we must also wait for any close that is in progress
205 before the next open may complete */
206
207 retval = 0;
208 add_wait_queue(&port->open_wait, &wait);
209
210 /* The port lock protects the port counts */
211 spin_lock_irqsave(&port->lock, flags);
212 if (!tty_hung_up_p(filp))
213 port->count--;
214 port->blocked_open++;
215 spin_unlock_irqrestore(&port->lock, flags);
216
217 while (1) {
218 /* Indicate we are open */
7834909f
AC
219 if (tty->termios->c_cflag & CBAUD)
220 tty_port_raise_dtr_rts(port);
36c621d8
AC
221
222 set_current_state(TASK_INTERRUPTIBLE);
223 /* Check for a hangup or uninitialised port. Return accordingly */
224 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
225 if (port->flags & ASYNC_HUP_NOTIFY)
226 retval = -EAGAIN;
227 else
228 retval = -ERESTARTSYS;
229 break;
230 }
231 /* Probe the carrier. For devices with no carrier detect this
232 will always return true */
233 cd = tty_port_carrier_raised(port);
234 if (!(port->flags & ASYNC_CLOSING) &&
235 (do_clocal || cd))
236 break;
237 if (signal_pending(current)) {
238 retval = -ERESTARTSYS;
239 break;
240 }
241 schedule();
242 }
243 set_current_state(TASK_RUNNING);
244 remove_wait_queue(&port->open_wait, &wait);
245
246 /* Update counts. A parallel hangup will have set count to zero and
247 we must not mess that up further */
248 spin_lock_irqsave(&port->lock, flags);
249 if (!tty_hung_up_p(filp))
250 port->count++;
251 port->blocked_open--;
252 if (retval == 0)
253 port->flags |= ASYNC_NORMAL_ACTIVE;
254 spin_unlock_irqrestore(&port->lock, flags);
255 return 0;
256
257}
258EXPORT_SYMBOL(tty_port_block_til_ready);
259
a6614999
AC
260int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
261{
262 unsigned long flags;
263
264 spin_lock_irqsave(&port->lock, flags);
265 if (tty_hung_up_p(filp)) {
266 spin_unlock_irqrestore(&port->lock, flags);
267 return 0;
268 }
269
270 if( tty->count == 1 && port->count != 1) {
271 printk(KERN_WARNING
272 "tty_port_close_start: tty->count = 1 port count = %d.\n",
273 port->count);
274 port->count = 1;
275 }
276 if (--port->count < 0) {
277 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
278 port->count);
279 port->count = 0;
280 }
281
282 if (port->count) {
283 spin_unlock_irqrestore(&port->lock, flags);
284 return 0;
285 }
286 port->flags |= ASYNC_CLOSING;
287 tty->closing = 1;
288 spin_unlock_irqrestore(&port->lock, flags);
fba85e01
AC
289 /* Don't block on a stalled port, just pull the chain */
290 if (tty->flow_stopped)
291 tty_driver_flush_buffer(tty);
6ed1dbae
AC
292 if (port->flags & ASYNC_INITIALIZED &&
293 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
a6614999
AC
294 tty_wait_until_sent(tty, port->closing_wait);
295 return 1;
296}
297EXPORT_SYMBOL(tty_port_close_start);
298
299void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
300{
301 unsigned long flags;
302
303 tty_ldisc_flush(tty);
304
305 spin_lock_irqsave(&port->lock, flags);
306 tty->closing = 0;
307
308 if (port->blocked_open) {
309 spin_unlock_irqrestore(&port->lock, flags);
310 if (port->close_delay) {
311 msleep_interruptible(
312 jiffies_to_msecs(port->close_delay));
313 }
314 spin_lock_irqsave(&port->lock, flags);
315 wake_up_interruptible(&port->open_wait);
316 }
317 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
318 wake_up_interruptible(&port->close_wait);
319 spin_unlock_irqrestore(&port->lock, flags);
320}
321EXPORT_SYMBOL(tty_port_close_end);
This page took 0.083357 seconds and 5 git commands to generate.