diff options
| -rw-r--r-- | drivers/char/cyclades.c | 302 |
1 files changed, 108 insertions, 194 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e2f731b70763..9e0cd7020aef 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
| @@ -2172,199 +2172,6 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) | |||
| 2172 | * ------------------------------------------------------------ | 2172 | * ------------------------------------------------------------ |
| 2173 | */ | 2173 | */ |
| 2174 | 2174 | ||
| 2175 | static int | ||
| 2176 | block_til_ready(struct tty_struct *tty, struct file *filp, | ||
| 2177 | struct cyclades_port *info) | ||
| 2178 | { | ||
| 2179 | DECLARE_WAITQUEUE(wait, current); | ||
| 2180 | struct cyclades_card *cinfo; | ||
| 2181 | unsigned long flags; | ||
| 2182 | int chip, channel, index; | ||
| 2183 | int retval; | ||
| 2184 | void __iomem *base_addr; | ||
| 2185 | |||
| 2186 | cinfo = info->card; | ||
| 2187 | channel = info->line - cinfo->first_line; | ||
| 2188 | |||
| 2189 | /* | ||
| 2190 | * If the device is in the middle of being closed, then block | ||
| 2191 | * until it's done, and then try again. | ||
| 2192 | */ | ||
| 2193 | if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { | ||
| 2194 | wait_event_interruptible(info->port.close_wait, | ||
| 2195 | !(info->port.flags & ASYNC_CLOSING)); | ||
| 2196 | return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | /* | ||
| 2200 | * If non-blocking mode is set, then make the check up front | ||
| 2201 | * and then exit. | ||
| 2202 | */ | ||
| 2203 | if ((filp->f_flags & O_NONBLOCK) || | ||
| 2204 | (tty->flags & (1 << TTY_IO_ERROR))) { | ||
| 2205 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | ||
| 2206 | return 0; | ||
| 2207 | } | ||
| 2208 | |||
| 2209 | /* | ||
| 2210 | * Block waiting for the carrier detect and the line to become | ||
| 2211 | * free (i.e., not in use by the callout). While we are in | ||
| 2212 | * this loop, info->port.count is dropped by one, so that | ||
| 2213 | * cy_close() knows when to free things. We restore it upon | ||
| 2214 | * exit, either normal or abnormal. | ||
| 2215 | */ | ||
| 2216 | retval = 0; | ||
| 2217 | add_wait_queue(&info->port.open_wait, &wait); | ||
| 2218 | #ifdef CY_DEBUG_OPEN | ||
| 2219 | printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, " | ||
| 2220 | "count = %d\n", info->line, info->port.count); | ||
| 2221 | #endif | ||
| 2222 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
| 2223 | if (!tty_hung_up_p(filp)) | ||
| 2224 | info->port.count--; | ||
| 2225 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
| 2226 | #ifdef CY_DEBUG_COUNT | ||
| 2227 | printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to " | ||
| 2228 | "%d\n", current->pid, info->port.count); | ||
| 2229 | #endif | ||
| 2230 | info->port.blocked_open++; | ||
| 2231 | |||
| 2232 | if (!cy_is_Z(cinfo)) { | ||
| 2233 | chip = channel >> 2; | ||
| 2234 | channel &= 0x03; | ||
| 2235 | index = cinfo->bus_index; | ||
| 2236 | base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); | ||
| 2237 | |||
| 2238 | while (1) { | ||
| 2239 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
| 2240 | if ((tty->termios->c_cflag & CBAUD)) { | ||
| 2241 | cy_writeb(base_addr + (CyCAR << index), | ||
| 2242 | (u_char) channel); | ||
| 2243 | cy_writeb(base_addr + (CyMSVR1 << index), | ||
| 2244 | CyRTS); | ||
| 2245 | cy_writeb(base_addr + (CyMSVR2 << index), | ||
| 2246 | CyDTR); | ||
| 2247 | #ifdef CY_DEBUG_DTR | ||
| 2248 | printk(KERN_DEBUG "cyc:block_til_ready raising " | ||
| 2249 | "DTR\n"); | ||
| 2250 | printk(KERN_DEBUG " status: 0x%x, 0x%x\n", | ||
| 2251 | readb(base_addr + (CyMSVR1 << index)), | ||
| 2252 | readb(base_addr + (CyMSVR2 << index))); | ||
| 2253 | #endif | ||
| 2254 | } | ||
| 2255 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
| 2256 | |||
| 2257 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 2258 | if (tty_hung_up_p(filp) || | ||
| 2259 | !(info->port.flags & ASYNC_INITIALIZED)) { | ||
| 2260 | retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? | ||
| 2261 | -EAGAIN : -ERESTARTSYS); | ||
| 2262 | break; | ||
| 2263 | } | ||
| 2264 | |||
| 2265 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
| 2266 | cy_writeb(base_addr + (CyCAR << index), | ||
| 2267 | (u_char) channel); | ||
| 2268 | if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || | ||
| 2269 | (readb(base_addr + | ||
| 2270 | (CyMSVR1 << index)) & CyDCD))) { | ||
| 2271 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
| 2272 | break; | ||
| 2273 | } | ||
| 2274 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
| 2275 | |||
| 2276 | if (signal_pending(current)) { | ||
| 2277 | retval = -ERESTARTSYS; | ||
| 2278 | break; | ||
| 2279 | } | ||
| 2280 | #ifdef CY_DEBUG_OPEN | ||
| 2281 | printk(KERN_DEBUG "cyc block_til_ready blocking: " | ||
| 2282 | "ttyC%d, count = %d\n", | ||
| 2283 | info->line, info->port.count); | ||
| 2284 | #endif | ||
| 2285 | schedule(); | ||
| 2286 | } | ||
| 2287 | } else { | ||
| 2288 | struct FIRM_ID __iomem *firm_id; | ||
| 2289 | struct ZFW_CTRL __iomem *zfw_ctrl; | ||
| 2290 | struct BOARD_CTRL __iomem *board_ctrl; | ||
| 2291 | struct CH_CTRL __iomem *ch_ctrl; | ||
| 2292 | |||
| 2293 | base_addr = cinfo->base_addr; | ||
| 2294 | firm_id = base_addr + ID_ADDRESS; | ||
| 2295 | if (!cyz_is_loaded(cinfo)) { | ||
| 2296 | __set_current_state(TASK_RUNNING); | ||
| 2297 | remove_wait_queue(&info->port.open_wait, &wait); | ||
| 2298 | return -EINVAL; | ||
| 2299 | } | ||
| 2300 | |||
| 2301 | zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr) | ||
| 2302 | & 0xfffff); | ||
| 2303 | board_ctrl = &zfw_ctrl->board_ctrl; | ||
| 2304 | ch_ctrl = zfw_ctrl->ch_ctrl; | ||
| 2305 | |||
| 2306 | while (1) { | ||
| 2307 | if ((tty->termios->c_cflag & CBAUD)) { | ||
| 2308 | cy_writel(&ch_ctrl[channel].rs_control, | ||
| 2309 | readl(&ch_ctrl[channel].rs_control) | | ||
| 2310 | C_RS_RTS | C_RS_DTR); | ||
| 2311 | retval = cyz_issue_cmd(cinfo, | ||
| 2312 | channel, C_CM_IOCTLM, 0L); | ||
| 2313 | if (retval != 0) { | ||
| 2314 | printk(KERN_ERR "cyc:block_til_ready " | ||
| 2315 | "retval on ttyC%d was %x\n", | ||
| 2316 | info->line, retval); | ||
| 2317 | } | ||
| 2318 | #ifdef CY_DEBUG_DTR | ||
| 2319 | printk(KERN_DEBUG "cyc:block_til_ready raising " | ||
| 2320 | "Z DTR\n"); | ||
| 2321 | #endif | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 2325 | if (tty_hung_up_p(filp) || | ||
| 2326 | !(info->port.flags & ASYNC_INITIALIZED)) { | ||
| 2327 | retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? | ||
| 2328 | -EAGAIN : -ERESTARTSYS); | ||
| 2329 | break; | ||
| 2330 | } | ||
| 2331 | if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || | ||
| 2332 | (readl(&ch_ctrl[channel].rs_status) & | ||
| 2333 | C_RS_DCD))) { | ||
| 2334 | break; | ||
| 2335 | } | ||
| 2336 | if (signal_pending(current)) { | ||
| 2337 | retval = -ERESTARTSYS; | ||
| 2338 | break; | ||
| 2339 | } | ||
| 2340 | #ifdef CY_DEBUG_OPEN | ||
| 2341 | printk(KERN_DEBUG "cyc block_til_ready blocking: " | ||
| 2342 | "ttyC%d, count = %d\n", | ||
| 2343 | info->line, info->port.count); | ||
| 2344 | #endif | ||
| 2345 | schedule(); | ||
| 2346 | } | ||
| 2347 | } | ||
| 2348 | __set_current_state(TASK_RUNNING); | ||
| 2349 | remove_wait_queue(&info->port.open_wait, &wait); | ||
| 2350 | if (!tty_hung_up_p(filp)) { | ||
| 2351 | info->port.count++; | ||
| 2352 | #ifdef CY_DEBUG_COUNT | ||
| 2353 | printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing " | ||
| 2354 | "count to %d\n", current->pid, info->port.count); | ||
| 2355 | #endif | ||
| 2356 | } | ||
| 2357 | info->port.blocked_open--; | ||
| 2358 | #ifdef CY_DEBUG_OPEN | ||
| 2359 | printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, " | ||
| 2360 | "count = %d\n", info->line, info->port.count); | ||
| 2361 | #endif | ||
| 2362 | if (retval) | ||
| 2363 | return retval; | ||
| 2364 | info->port.flags |= ASYNC_NORMAL_ACTIVE; | ||
