diff options
author | Alan Cox <alan@redhat.com> | 2009-01-02 08:45:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-02 13:19:38 -0500 |
commit | 31f35939d1d9bcfb3099b32c67b896d2792603f9 (patch) | |
tree | 39b6ceaf0e7477e0357ff8235814f579adad3f28 /drivers/char/esp.c | |
parent | c9b3976e3fec266be25c5001a70aa0a890b6c476 (diff) |
tty_port: Add a port level carrier detect operation
This is the first step to generalising the various pieces of waiting logic
duplicated in all sorts of serial drivers.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/esp.c')
-rw-r--r-- | drivers/char/esp.c | 61 |
1 files changed, 37 insertions, 24 deletions
diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 7f077c0097f6..45ec263ec012 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c | |||
@@ -2054,6 +2054,15 @@ static void esp_hangup(struct tty_struct *tty) | |||
2054 | wake_up_interruptible(&info->port.open_wait); | 2054 | wake_up_interruptible(&info->port.open_wait); |
2055 | } | 2055 | } |
2056 | 2056 | ||
2057 | static int esp_carrier_raised(struct tty_port *port) | ||
2058 | { | ||
2059 | struct esp_struct *info = container_of(port, struct esp_struct, port); | ||
2060 | serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); | ||
2061 | if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) | ||
2062 | return 1; | ||
2063 | return 0; | ||
2064 | } | ||
2065 | |||
2057 | /* | 2066 | /* |
2058 | * ------------------------------------------------------------ | 2067 | * ------------------------------------------------------------ |
2059 | * esp_open() and friends | 2068 | * esp_open() and friends |
@@ -2066,17 +2075,19 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
2066 | int retval; | 2075 | int retval; |
2067 | int do_clocal = 0; | 2076 | int do_clocal = 0; |
2068 | unsigned long flags; | 2077 | unsigned long flags; |
2078 | int cd; | ||
2079 | struct tty_port *port = &info->port; | ||
2069 | 2080 | ||
2070 | /* | 2081 | /* |
2071 | * If the device is in the middle of being closed, then block | 2082 | * If the device is in the middle of being closed, then block |
2072 | * until it's done, and then try again. | 2083 | * until it's done, and then try again. |
2073 | */ | 2084 | */ |
2074 | if (tty_hung_up_p(filp) || | 2085 | if (tty_hung_up_p(filp) || |
2075 | (info->port.flags & ASYNC_CLOSING)) { | 2086 | (port->flags & ASYNC_CLOSING)) { |
2076 | if (info->port.flags & ASYNC_CLOSING) | 2087 | if (port->flags & ASYNC_CLOSING) |
2077 | interruptible_sleep_on(&info->port.close_wait); | 2088 | interruptible_sleep_on(&port->close_wait); |
2078 | #ifdef SERIAL_DO_RESTART | 2089 | #ifdef SERIAL_DO_RESTART |
2079 | if (info->port.flags & ASYNC_HUP_NOTIFY) | 2090 | if (port->flags & ASYNC_HUP_NOTIFY) |
2080 | return -EAGAIN; | 2091 | return -EAGAIN; |
2081 | else | 2092 | else |
2082 | return -ERESTARTSYS; | 2093 | return -ERESTARTSYS; |
@@ -2091,7 +2102,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
2091 | */ | 2102 | */ |
2092 | if ((filp->f_flags & O_NONBLOCK) || | 2103 | if ((filp->f_flags & O_NONBLOCK) || |
2093 | (tty->flags & (1 << TTY_IO_ERROR))) { | 2104 | (tty->flags & (1 << TTY_IO_ERROR))) { |
2094 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | 2105 | port->flags |= ASYNC_NORMAL_ACTIVE; |
2095 | return 0; | 2106 | return 0; |
2096 | } | 2107 | } |
2097 | 2108 | ||
@@ -2101,20 +2112,20 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
2101 | /* | 2112 | /* |
2102 | * Block waiting for the carrier detect and the line to become | 2113 | * Block waiting for the carrier detect and the line to become |
2103 | * free (i.e., not in use by the callout). While we are in | 2114 | * free (i.e., not in use by the callout). While we are in |
2104 | * this loop, info->port.count is dropped by one, so that | 2115 | * this loop, port->count is dropped by one, so that |
2105 | * rs_close() knows when to free things. We restore it upon | 2116 | * rs_close() knows when to free things. We restore it upon |
2106 | * exit, either normal or abnormal. | 2117 | * exit, either normal or abnormal. |
2107 | */ | 2118 | */ |
2108 | retval = 0; | 2119 | retval = 0; |
2109 | add_wait_queue(&info->port.open_wait, &wait); | 2120 | add_wait_queue(&port->open_wait, &wait); |
2110 | #ifdef SERIAL_DEBUG_OPEN | 2121 | #ifdef SERIAL_DEBUG_OPEN |
2111 | printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n", | 2122 | printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n", |
2112 | info->line, info->port.count); | 2123 | info->line, port->count); |
2113 | #endif | 2124 | #endif |
2114 | spin_lock_irqsave(&info->lock, flags); | 2125 | spin_lock_irqsave(&info->lock, flags); |
2115 | if (!tty_hung_up_p(filp)) | 2126 | if (!tty_hung_up_p(filp)) |
2116 | info->port.count--; | 2127 | port->count--; |
2117 | info->port.blocked_open++; | 2128 | port->blocked_open++; |
2118 | while (1) { | 2129 | while (1) { |
2119 | if ((tty->termios->c_cflag & CBAUD)) { | 2130 | if ((tty->termios->c_cflag & CBAUD)) { |
2120 | unsigned int scratch; | 2131 | unsigned int scratch; |
@@ -2129,9 +2140,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
2129 | } | 2140 | } |
2130 | set_current_state(TASK_INTERRUPTIBLE); | 2141 | set_current_state(TASK_INTERRUPTIBLE); |
2131 | if (tty_hung_up_p(filp) || | 2142 | if (tty_hung_up_p(filp) || |
2132 | !(info->port.flags & ASYNC_INITIALIZED)) { | 2143 | !(port->flags & ASYNC_INITIALIZED)) { |
2133 | #ifdef SERIAL_DO_RESTART | 2144 | #ifdef SERIAL_DO_RESTART |
2134 | if (info->port.flags & ASYNC_HUP_NOTIFY) | 2145 | if (port->flags & ASYNC_HUP_NOTIFY) |
2135 | retval = -EAGAIN; | 2146 | retval = -EAGAIN; |
2136 | else | 2147 | else |
2137 | retval = -ERESTARTSYS; | 2148 | retval = -ERESTARTSYS; |
@@ -2141,11 +2152,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
2141 | break; | 2152 | break; |
2142 | } | 2153 | } |
2143 | 2154 | ||
2144 | serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); | 2155 | cd = tty_port_carrier_raised(port); |
2145 | if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) | ||
2146 | do_clocal = 1; | ||
2147 | 2156 | ||
2148 | if (!(info->port.flags & ASYNC_CLOSING) && | 2157 | if (!(port->flags & ASYNC_CLOSING) && |
2149 | (do_clocal)) | 2158 | (do_clocal)) |
2150 | break; | 2159 | break; |
2151 | if (signal_pending(current)) { | 2160 | if (signal_pending(current)) { |
@@ -2154,25 +2163,25 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
2154 | } | 2163 | } |
2155 | #ifdef SERIAL_DEBUG_OPEN | 2164 | #ifdef SERIAL_DEBUG_OPEN |
2156 | printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n", | 2165 | printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n", |
2157 | info->line, info->port.count); | 2166 | info->line, port->count); |
2158 | #endif | 2167 | #endif |
2159 | spin_unlock_irqrestore(&info->lock, flags); | 2168 | spin_unlock_irqrestore(&info->lock, flags); |
2160 | schedule(); | 2169 | schedule(); |
2161 | spin_lock_irqsave(&info->lock, flags); | 2170 | spin_lock_irqsave(&info->lock, flags); |
2162 | } | 2171 | } |
2163 | set_current_state(TASK_RUNNING); | 2172 | set_current_state(TASK_RUNNING); |
2164 | remove_wait_queue(&info->port.open_wait, &wait); | 2173 | remove_wait_queue(&port->open_wait, &wait); |
2165 | if (!tty_hung_up_p(filp)) | 2174 | if (!tty_hung_up_p(filp)) |
2166 | info->port.count++; | 2175 | port->count++; |
2167 | info->port.blocked_open--; | 2176 | port->blocked_open--; |
2168 | spin_unlock_irqrestore(&info->lock, flags); | 2177 | spin_unlock_irqrestore(&info->lock, flags); |
2169 | #ifdef SERIAL_DEBUG_OPEN | 2178 | #ifdef SERIAL_DEBUG_OPEN |
2170 | printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n", | 2179 | printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n", |
2171 | info->line, info->port.count); | 2180 | info->line, port->count); |
2172 | #endif | 2181 | #endif |
2173 | if (retval) | 2182 | if (retval) |
2174 | return retval; | 2183 | return retval; |
2175 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | 2184 | port->flags |= ASYNC_NORMAL_ACTIVE; |
2176 | return 0; | 2185 | return 0; |
2177 | } | 2186 | } |
2178 | 2187 | ||
@@ -2329,6 +2338,10 @@ static const struct tty_operations esp_ops = { | |||
2329 | .tiocmset = esp_tiocmset, | 2338 | .tiocmset = esp_tiocmset, |
2330 | }; | 2339 | }; |
2331 | 2340 | ||
2341 | static const struct tty_port_operations esp_port_ops = { | ||
2342 | .esp_carrier_raised, | ||
2343 | }; | ||
2344 | |||
2332 | /* | 2345 | /* |
2333 | * The serial driver boot-time initialization code! | 2346 | * The serial driver boot-time initialization code! |
2334 | */ | 2347 | */ |
@@ -2415,6 +2428,8 @@ static int __init espserial_init(void) | |||
2415 | offset = 0; | 2428 | offset = 0; |
2416 | 2429 | ||
2417 | do { | 2430 | do { |
2431 | tty_port_init(&info->port); | ||
2432 | info->port.ops = &esp_port_ops; | ||
2418 | info->io_port = esp[i] + offset; | 2433 | info->io_port = esp[i] + offset; |
2419 | info->irq = irq[i]; | 2434 | info->irq = irq[i]; |
2420 | info->line = (i * 8) + (offset / 8); | 2435 | info->line = (i * 8) + (offset / 8); |
@@ -2437,8 +2452,6 @@ static int __init espserial_init(void) | |||
2437 | info->config.flow_off = flow_off; | 2452 | info->config.flow_off = flow_off; |
2438 | info->config.pio_threshold = pio_threshold; | 2453 | info->config.pio_threshold = pio_threshold; |
2439 | info->next_port = ports; | 2454 | info->next_port = ports; |
2440 | init_waitqueue_head(&info->port.open_wait); | ||
2441 | init_waitqueue_head(&info->port.close_wait); | ||
2442 | init_waitqueue_head(&info->delta_msr_wait); | 2455 | init_waitqueue_head(&info->delta_msr_wait); |
2443 | init_waitqueue_head(&info->break_wait); | 2456 | init_waitqueue_head(&info->break_wait); |
2444 | ports = info; | 2457 | ports = info; |