• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
tty_port_init(struct tty_port * port)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 
tty_port_alloc_xmit_buf(struct tty_port * port)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 
tty_port_free_xmit_buf(struct tty_port * port)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 
tty_port_tty_get(struct tty_port * port)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 
tty_port_tty_set(struct tty_port * port,struct tty_struct * tty)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 
tty_port_hangup(struct tty_port * port)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 
tty_port_carrier_raised(struct tty_port * port)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	-	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 
tty_port_raise_dtr_rts(struct tty_port * port)148 void 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 }
153 EXPORT_SYMBOL(tty_port_raise_dtr_rts);
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 
tty_port_block_til_ready(struct tty_port * port,struct tty_struct * tty,struct file * filp)175 int 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 */
219 		if (tty->termios->c_cflag & CBAUD)
220 			tty_port_raise_dtr_rts(port);
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 }
258 EXPORT_SYMBOL(tty_port_block_til_ready);
259 
tty_port_close_start(struct tty_port * port,struct tty_struct * tty,struct file * filp)260 int 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);
289 	/* Don't block on a stalled port, just pull the chain */
290 	if (tty->flow_stopped)
291 		tty_driver_flush_buffer(tty);
292 	if (port->flags & ASYNC_INITIALIZED &&
293 			port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
294 		tty_wait_until_sent(tty, port->closing_wait);
295 	return 1;
296 }
297 EXPORT_SYMBOL(tty_port_close_start);
298 
tty_port_close_end(struct tty_port * port,struct tty_struct * tty)299 void 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 }
321 EXPORT_SYMBOL(tty_port_close_end);
322