Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.31 350 lines 9.0 kB view raw
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 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); 27 spin_lock_init(&port->lock); 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 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); 94 port->tty = tty_kref_get(tty); 95 spin_unlock_irqrestore(&port->lock, flags); 96} 97EXPORT_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 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 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); 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 148void tty_port_raise_dtr_rts(struct tty_port *port) 149{ 150 if (port->ops->dtr_rts) 151 port->ops->dtr_rts(port, 1); 152} 153EXPORT_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 164void tty_port_lower_dtr_rts(struct tty_port *port) 165{ 166 if (port->ops->dtr_rts) 167 port->ops->dtr_rts(port, 0); 168} 169EXPORT_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 191int 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 DEFINE_WAIT(wait); 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 226 /* The port lock protects the port counts */ 227 spin_lock_irqsave(&port->lock, flags); 228 if (!tty_hung_up_p(filp)) 229 port->count--; 230 port->blocked_open++; 231 spin_unlock_irqrestore(&port->lock, flags); 232 233 while (1) { 234 /* Indicate we are open */ 235 if (tty->termios->c_cflag & CBAUD) 236 tty_port_raise_dtr_rts(port); 237 238 prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); 239 /* Check for a hangup or uninitialised port. Return accordingly */ 240 if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { 241 if (port->flags & ASYNC_HUP_NOTIFY) 242 retval = -EAGAIN; 243 else 244 retval = -ERESTARTSYS; 245 break; 246 } 247 /* Probe the carrier. For devices with no carrier detect this 248 will always return true */ 249 cd = tty_port_carrier_raised(port); 250 if (!(port->flags & ASYNC_CLOSING) && 251 (do_clocal || cd)) 252 break; 253 if (signal_pending(current)) { 254 retval = -ERESTARTSYS; 255 break; 256 } 257 schedule(); 258 } 259 finish_wait(&port->open_wait, &wait); 260 261 /* Update counts. A parallel hangup will have set count to zero and 262 we must not mess that up further */ 263 spin_lock_irqsave(&port->lock, flags); 264 if (!tty_hung_up_p(filp)) 265 port->count++; 266 port->blocked_open--; 267 if (retval == 0) 268 port->flags |= ASYNC_NORMAL_ACTIVE; 269 spin_unlock_irqrestore(&port->lock, flags); 270 return retval; 271 272} 273EXPORT_SYMBOL(tty_port_block_til_ready); 274 275int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) 276{ 277 unsigned long flags; 278 279 spin_lock_irqsave(&port->lock, flags); 280 if (tty_hung_up_p(filp)) { 281 spin_unlock_irqrestore(&port->lock, flags); 282 return 0; 283 } 284 285 if( tty->count == 1 && port->count != 1) { 286 printk(KERN_WARNING 287 "tty_port_close_start: tty->count = 1 port count = %d.\n", 288 port->count); 289 port->count = 1; 290 } 291 if (--port->count < 0) { 292 printk(KERN_WARNING "tty_port_close_start: count = %d\n", 293 port->count); 294 port->count = 0; 295 } 296 297 if (port->count) { 298 spin_unlock_irqrestore(&port->lock, flags); 299 return 0; 300 } 301 port->flags |= ASYNC_CLOSING; 302 tty->closing = 1; 303 spin_unlock_irqrestore(&port->lock, flags); 304 /* Don't block on a stalled port, just pull the chain */ 305 if (tty->flow_stopped) 306 tty_driver_flush_buffer(tty); 307 if (port->flags & ASYNC_INITIALIZED && 308 port->closing_wait != ASYNC_CLOSING_WAIT_NONE) 309 tty_wait_until_sent(tty, port->closing_wait); 310 if (port->drain_delay) { 311 unsigned int bps = tty_get_baud_rate(tty); 312 long timeout; 313 314 if (bps > 1200) 315 timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps, 316 HZ / 10); 317 else 318 timeout = 2 * HZ; 319 schedule_timeout_interruptible(timeout); 320 } 321 return 1; 322} 323EXPORT_SYMBOL(tty_port_close_start); 324 325void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) 326{ 327 unsigned long flags; 328 329 tty_ldisc_flush(tty); 330 331 if (tty->termios->c_cflag & HUPCL) 332 tty_port_lower_dtr_rts(port); 333 334 spin_lock_irqsave(&port->lock, flags); 335 tty->closing = 0; 336 337 if (port->blocked_open) { 338 spin_unlock_irqrestore(&port->lock, flags); 339 if (port->close_delay) { 340 msleep_interruptible( 341 jiffies_to_msecs(port->close_delay)); 342 } 343 spin_lock_irqsave(&port->lock, flags); 344 wake_up_interruptible(&port->open_wait); 345 } 346 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); 347 wake_up_interruptible(&port->close_wait); 348 spin_unlock_irqrestore(&port->lock, flags); 349} 350EXPORT_SYMBOL(tty_port_close_end);