1
2
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
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 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}
32EXPORT_SYMBOL(tty_port_init);
33
34int tty_port_alloc_xmit_buf(struct tty_port *port)
35{
36
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}
45EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
46
47void 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}
56EXPORT_SYMBOL(tty_port_free_xmit_buf);
57
58
59
60
61
62
63
64
65
66
67struct 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}
77EXPORT_SYMBOL(tty_port_tty_get);
78
79
80
81
82
83
84
85
86
87
88void 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}
98EXPORT_SYMBOL(tty_port_tty_set);
99
100static void tty_port_shutdown(struct tty_port *port)
101{
102 if (port->ops->shutdown &&
103 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
104 port->ops->shutdown(port);
105
106}
107
108
109
110
111
112
113
114
115
116void tty_port_hangup(struct tty_port *port)
117{
118 unsigned long flags;
119
120 spin_lock_irqsave(&port->lock, flags);
121 port->count = 0;
122 port->flags &= ~ASYNC_NORMAL_ACTIVE;
123 if (port->tty)
124 tty_kref_put(port->tty);
125 port->tty = NULL;
126 spin_unlock_irqrestore(&port->lock, flags);
127 wake_up_interruptible(&port->open_wait);
128 wake_up_interruptible(&port->delta_msr_wait);
129 tty_port_shutdown(port);
130}
131EXPORT_SYMBOL(tty_port_hangup);
132
133
134
135
136
137
138
139
140
141
142int tty_port_carrier_raised(struct tty_port *port)
143{
144 if (port->ops->carrier_raised == NULL)
145 return 1;
146 return port->ops->carrier_raised(port);
147}
148EXPORT_SYMBOL(tty_port_carrier_raised);
149
150
151
152
153
154
155
156
157
158
159void tty_port_raise_dtr_rts(struct tty_port *port)
160{
161 if (port->ops->dtr_rts)
162 port->ops->dtr_rts(port, 1);
163}
164EXPORT_SYMBOL(tty_port_raise_dtr_rts);
165
166
167
168
169
170
171
172
173
174
175void tty_port_lower_dtr_rts(struct tty_port *port)
176{
177 if (port->ops->dtr_rts)
178 port->ops->dtr_rts(port, 0);
179}
180EXPORT_SYMBOL(tty_port_lower_dtr_rts);
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202int tty_port_block_til_ready(struct tty_port *port,
203 struct tty_struct *tty, struct file *filp)
204{
205 int do_clocal = 0, retval;
206 unsigned long flags;
207 DEFINE_WAIT(wait);
208 int cd;
209
210
211 if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
212 wait_event_interruptible(port->close_wait,
213 !(port->flags & ASYNC_CLOSING));
214 if (port->flags & ASYNC_HUP_NOTIFY)
215 return -EAGAIN;
216 else
217 return -ERESTARTSYS;
218 }
219
220
221
222 if (tty->flags & (1 << TTY_IO_ERROR)) {
223 port->flags |= ASYNC_NORMAL_ACTIVE;
224 return 0;
225 }
226 if (filp->f_flags & O_NONBLOCK) {
227
228 if (tty->termios->c_cflag & CBAUD)
229 tty_port_raise_dtr_rts(port);
230 port->flags |= ASYNC_NORMAL_ACTIVE;
231 return 0;
232 }
233
234 if (C_CLOCAL(tty))
235 do_clocal = 1;
236
237
238
239
240
241 retval = 0;
242
243
244 spin_lock_irqsave(&port->lock, flags);
245 if (!tty_hung_up_p(filp))
246 port->count--;
247 port->blocked_open++;
248 spin_unlock_irqrestore(&port->lock, flags);
249
250 while (1) {
251
252 if (tty->termios->c_cflag & CBAUD)
253 tty_port_raise_dtr_rts(port);
254
255 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
256
257 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
258 if (port->flags & ASYNC_HUP_NOTIFY)
259 retval = -EAGAIN;
260 else
261 retval = -ERESTARTSYS;
262 break;
263 }
264
265
266 cd = tty_port_carrier_raised(port);
267 if (!(port->flags & ASYNC_CLOSING) &&
268 (do_clocal || cd))
269 break;
270 if (signal_pending(current)) {
271 retval = -ERESTARTSYS;
272 break;
273 }
274 schedule();
275 }
276 finish_wait(&port->open_wait, &wait);
277
278
279
280 spin_lock_irqsave(&port->lock, flags);
281 if (!tty_hung_up_p(filp))
282 port->count++;
283 port->blocked_open--;
284 if (retval == 0)
285 port->flags |= ASYNC_NORMAL_ACTIVE;
286 spin_unlock_irqrestore(&port->lock, flags);
287 return retval;
288
289}
290EXPORT_SYMBOL(tty_port_block_til_ready);
291
292int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp)
293{
294 unsigned long flags;
295
296 spin_lock_irqsave(&port->lock, flags);
297 if (tty_hung_up_p(filp)) {
298 spin_unlock_irqrestore(&port->lock, flags);
299 return 0;
300 }
301
302 if( tty->count == 1 && port->count != 1) {
303 printk(KERN_WARNING
304 "tty_port_close_start: tty->count = 1 port count = %d.\n",
305 port->count);
306 port->count = 1;
307 }
308 if (--port->count < 0) {
309 printk(KERN_WARNING "tty_port_close_start: count = %d\n",
310 port->count);
311 port->count = 0;
312 }
313
314 if (port->count) {
315 spin_unlock_irqrestore(&port->lock, flags);
316 if (port->ops->drop)
317 port->ops->drop(port);
318 return 0;
319 }
320 set_bit(ASYNCB_CLOSING, &port->flags);
321 tty->closing = 1;
322 spin_unlock_irqrestore(&port->lock, flags);
323
324 if (tty->flow_stopped)
325 tty_driver_flush_buffer(tty);
326 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
327 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
328 tty_wait_until_sent(tty, port->closing_wait);
329 if (port->drain_delay) {
330 unsigned int bps = tty_get_baud_rate(tty);
331 long timeout;
332
333 if (bps > 1200)
334 timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
335 HZ / 10);
336 else
337 timeout = 2 * HZ;
338 schedule_timeout_interruptible(timeout);
339 }
340
341
342
343 return 1;
344}
345EXPORT_SYMBOL(tty_port_close_start);
346
347void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
348{
349 unsigned long flags;
350
351 tty_ldisc_flush(tty);
352
353 if (tty->termios->c_cflag & HUPCL)
354 tty_port_lower_dtr_rts(port);
355
356 spin_lock_irqsave(&port->lock, flags);
357 tty->closing = 0;
358
359 if (port->blocked_open) {
360 spin_unlock_irqrestore(&port->lock, flags);
361 if (port->close_delay) {
362 msleep_interruptible(
363 jiffies_to_msecs(port->close_delay));
364 }
365 spin_lock_irqsave(&port->lock, flags);
366 wake_up_interruptible(&port->open_wait);
367 }
368 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
369 wake_up_interruptible(&port->close_wait);
370 spin_unlock_irqrestore(&port->lock, flags);
371}
372EXPORT_SYMBOL(tty_port_close_end);
373
374void tty_port_close(struct tty_port *port, struct tty_struct *tty,
375 struct file *filp)
376{
377 if (tty_port_close_start(port, tty, filp) == 0)
378 return;
379 tty_port_shutdown(port);
380 tty_port_close_end(port, tty);
381 tty_port_tty_set(port, NULL);
382}
383EXPORT_SYMBOL(tty_port_close);
384