aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/cyclades.c
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2009-09-19 16:13:12 -0400
committerLive-CD User <linux@linux.site>2009-09-19 16:13:12 -0400
commitf0737579424dd2c4e68bdd54c718455a3f42c7b5 (patch)
tree32f332b945f816342f620deb2d5b3ce432d53b98 /drivers/char/cyclades.c
parentd13549f804d2965a9f279a8ff867f35d949572c8 (diff)
cyclades: remove block_til_ready
Use a tty_port common instead. This saves lots of .text and makes the code a lot more readable. This involves separation of a dtr_rts handling, next patches will use that to not duplicate the code all over the place. Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char/cyclades.c')
-rw-r--r--drivers/char/cyclades.c302
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
2175static int
2176block_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;
2365 return 0;
2366} /* block_til_ready */
2367
2368/* 2175/*
2369 * This routine is called whenever a serial port is opened. It 2176 * This routine is called whenever a serial port is opened. It
2370 * performs the serial-specific initialization for the tty structure. 2177 * performs the serial-specific initialization for the tty structure.
@@ -2472,7 +2279,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
2472 if (retval) 2279 if (retval)
2473 return retval; 2280 return retval;
2474 2281
2475 retval = block_til_ready(tty, filp, info); 2282 retval = tty_port_block_til_ready(&info->port, tty, filp);
2476 if (retval) { 2283 if (retval) {
2477#ifdef CY_DEBUG_OPEN 2284#ifdef CY_DEBUG_OPEN
2478 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " 2285 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
@@ -4312,6 +4119,111 @@ static void cy_hangup(struct tty_struct *tty)
4312 wake_up_interruptible(&info->port.open_wait); 4119 wake_up_interruptible(&info->port.open_wait);
4313} /* cy_hangup */ 4120} /* cy_hangup */
4314 4121
4122static int cyy_carrier_raised(struct tty_port *port)
4123{
4124 struct cyclades_port *info = container_of(port, struct cyclades_port,
4125 port);
4126 struct cyclades_card *cinfo = info->card;
4127 void __iomem *base = cinfo->base_addr;
4128 unsigned long flags;
4129 int channel = info->line - cinfo->first_line;
4130 int chip = channel >> 2, index = cinfo->bus_index;
4131 u32 cd;
4132
4133 channel &= 0x03;
4134 base += cy_chip_offset[chip] << index;
4135
4136 spin_lock_irqsave(&cinfo->card_lock, flags);
4137 cy_writeb(base + (CyCAR << index), (u8)channel);
4138 cd = readb(base + (CyMSVR1 << index)) & CyDCD;
4139 spin_unlock_irqrestore(&cinfo->card_lock, flags);
4140
4141 return cd;
4142}
4143
4144static void cyy_dtr_rts(struct tty_port *port, int raise)
4145{
4146 struct cyclades_port *info = container_of(port, struct cyclades_port,
4147 port);
4148 struct cyclades_card *cinfo = info->card;
4149 void __iomem *base = cinfo->base_addr;
4150 unsigned long flags;
4151 int channel = info->line - cinfo->first_line;
4152 int chip = channel >> 2, index = cinfo->bus_index;
4153
4154 channel &= 0x03;
4155 base += cy_chip_offset[chip] << index;
4156
4157 spin_lock_irqsave(&cinfo->card_lock, flags);
4158 cy_writeb(base + (CyCAR << index), (u8)channel);
4159 cy_writeb(base + (CyMSVR1 << index), raise ? CyRTS : ~CyRTS);
4160 cy_writeb(base + (CyMSVR2 << index), raise ? CyDTR : ~CyDTR);
4161#ifdef CY_DEBUG_DTR
4162 printk(KERN_DEBUG "%s: raising DTR\n", __func__);
4163 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
4164 readb(base + (CyMSVR1 << index)),
4165 readb(base + (CyMSVR2 << index)));
4166#endif
4167 spin_unlock_irqrestore(&cinfo->card_lock, flags);
4168}
4169
4170static int cyz_carrier_raised(struct tty_port *port)
4171{
4172 struct cyclades_port *info = container_of(port, struct cyclades_port,
4173 port);
4174 struct cyclades_card *cinfo = info->card;
4175 void __iomem *base = cinfo->base_addr;
4176 struct FIRM_ID __iomem *firm_id = base + ID_ADDRESS;
4177 struct ZFW_CTRL __iomem *zfw_ctrl;
4178 struct CH_CTRL __iomem *ch_ctrl;
4179 int channel = info->line - cinfo->first_line;
4180
4181 zfw_ctrl = base + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4182 ch_ctrl = zfw_ctrl->ch_ctrl;
4183
4184 return readl(&ch_ctrl[channel].rs_status) & C_RS_DCD;
4185}
4186
4187static void cyz_dtr_rts(struct tty_port *port, int raise)
4188{
4189 struct cyclades_port *info = container_of(port, struct cyclades_port,
4190 port);
4191 struct cyclades_card *cinfo = info->card;
4192 void __iomem *base = cinfo->base_addr;
4193 struct FIRM_ID __iomem *firm_id = base + ID_ADDRESS;
4194 struct ZFW_CTRL __iomem *zfw_ctrl;
4195 struct CH_CTRL __iomem *ch_ctrl;
4196 int ret, channel = info->line - cinfo->first_line;
4197 u32 rs;
4198
4199 zfw_ctrl = base + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
4200 ch_ctrl = zfw_ctrl->ch_ctrl;
4201
4202 rs = readl(&ch_ctrl[channel].rs_control);
4203 if (raise)
4204 rs |= C_RS_RTS | C_RS_DTR;
4205 else
4206 rs &= ~(C_RS_RTS | C_RS_DTR);
4207 cy_writel(&ch_ctrl[channel].rs_control, rs);
4208 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
4209 if (ret != 0)
4210 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
4211 __func__, info->line, ret);
4212#ifdef CY_DEBUG_DTR
4213 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
4214#endif
4215}
4216
4217static const struct tty_port_operations cyy_port_ops = {
4218 .carrier_raised = cyy_carrier_raised,
4219 .dtr_rts = cyy_dtr_rts,
4220};
4221
4222static const struct tty_port_operations cyz_port_ops = {
4223 .carrier_raised = cyz_carrier_raised,
4224 .dtr_rts = cyz_dtr_rts,
4225};
4226
4315/* 4227/*
4316 * --------------------------------------------------------------------- 4228 * ---------------------------------------------------------------------
4317 * cy_init() and friends 4229 * cy_init() and friends
@@ -4351,6 +4263,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
4351 init_waitqueue_head(&info->delta_msr_wait); 4263 init_waitqueue_head(&info->delta_msr_wait);
4352 4264
4353 if (cy_is_Z(cinfo)) { 4265 if (cy_is_Z(cinfo)) {
4266 info->port.ops = &cyz_port_ops;
4354 info->type = PORT_STARTECH; 4267 info->type = PORT_STARTECH;
4355 if (cinfo->hw_ver == ZO_V1) 4268 if (cinfo->hw_ver == ZO_V1)
4356 info->xmit_fifo_size = CYZ_FIFO_SIZE; 4269 info->xmit_fifo_size = CYZ_FIFO_SIZE;
@@ -4362,6 +4275,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
4362#endif 4275#endif
4363 } else { 4276 } else {
4364 int index = cinfo->bus_index; 4277 int index = cinfo->bus_index;
4278 info->port.ops = &cyy_port_ops;
4365 info->type = PORT_CIRRUS; 4279 info->type = PORT_CIRRUS;
4366 info->xmit_fifo_size = CyMAX_CHAR_FIFO; 4280 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
4367 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; 4281 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;