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.29 321 lines 8.3 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 - 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); 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 */ 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} 258EXPORT_SYMBOL(tty_port_block_til_ready); 259 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); 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} 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);