diff options
Diffstat (limited to 'drivers/tty/cyclades.c')
-rw-r--r-- | drivers/tty/cyclades.c | 297 |
1 files changed, 142 insertions, 155 deletions
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index b09c8d1f9a66..345bd0e0884e 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -441,7 +441,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, void __iomem *base_addr) { struct cyclades_port *info; - struct tty_struct *tty; + struct tty_port *port; int len, index = cinfo->bus_index; u8 ivr, save_xir, channel, save_car, data, char_count; @@ -452,22 +452,11 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, save_xir = readb(base_addr + (CyRIR << index)); channel = save_xir & CyIRChannel; info = &cinfo->ports[channel + chip * 4]; + port = &info->port; save_car = cyy_readb(info, CyCAR); cyy_writeb(info, CyCAR, save_xir); ivr = cyy_readb(info, CyRIVR) & CyIVRMask; - tty = tty_port_tty_get(&info->port); - /* if there is nowhere to put the data, discard it */ - if (tty == NULL) { - if (ivr == CyIVRRxEx) { /* exception */ - data = cyy_readb(info, CyRDSR); - } else { /* normal character reception */ - char_count = cyy_readb(info, CyRDCR); - while (char_count--) - data = cyy_readb(info, CyRDSR); - } - goto end; - } /* there is an open port for this data */ if (ivr == CyIVRRxEx) { /* exception */ data = cyy_readb(info, CyRDSR); @@ -484,40 +473,45 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, if (data & info->ignore_status_mask) { info->icount.rx++; - tty_kref_put(tty); return; } - if (tty_buffer_request_room(tty, 1)) { + if (tty_buffer_request_room(port, 1)) { if (data & info->read_status_mask) { if (data & CyBREAK) { - tty_insert_flip_char(tty, + tty_insert_flip_char(port, cyy_readb(info, CyRDSR), TTY_BREAK); info->icount.rx++; - if (info->port.flags & ASYNC_SAK) - do_SAK(tty); + if (port->flags & ASYNC_SAK) { + struct tty_struct *tty = + tty_port_tty_get(port); + if (tty) { + do_SAK(tty); + tty_kref_put(tty); + } + } } else if (data & CyFRAME) { - tty_insert_flip_char(tty, + tty_insert_flip_char(port, cyy_readb(info, CyRDSR), TTY_FRAME); info->icount.rx++; info->idle_stats.frame_errs++; } else if (data & CyPARITY) { /* Pieces of seven... */ - tty_insert_flip_char(tty, + tty_insert_flip_char(port, cyy_readb(info, CyRDSR), TTY_PARITY); info->icount.rx++; info->idle_stats.parity_errs++; } else if (data & CyOVERRUN) { - tty_insert_flip_char(tty, 0, + tty_insert_flip_char(port, 0, TTY_OVERRUN); info->icount.rx++; /* If the flip buffer itself is overflowing, we still lose the next incoming character. */ - tty_insert_flip_char(tty, + tty_insert_flip_char(port, cyy_readb(info, CyRDSR), TTY_FRAME); info->icount.rx++; @@ -527,12 +521,12 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, /* } else if(data & CyTIMEOUT) { */ /* } else if(data & CySPECHAR) { */ } else { - tty_insert_flip_char(tty, 0, + tty_insert_flip_char(port, 0, TTY_NORMAL); info->icount.rx++; } } else { - tty_insert_flip_char(tty, 0, TTY_NORMAL); + tty_insert_flip_char(port, 0, TTY_NORMAL); info->icount.rx++; } } else { @@ -552,10 +546,10 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, info->mon.char_max = char_count; info->mon.char_last = char_count; #endif - len = tty_buffer_request_room(tty, char_count); + len = tty_buffer_request_room(port, char_count); while (len--) { data = cyy_readb(info, CyRDSR); - tty_insert_flip_char(tty, data, TTY_NORMAL); + tty_insert_flip_char(port, data, TTY_NORMAL); info->idle_stats.recv_bytes++; info->icount.rx++; #ifdef CY_16Y_HACK @@ -564,9 +558,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, } info->idle_stats.recv_idle = jiffies; } - tty_schedule_flip(tty); - tty_kref_put(tty); -end: + tty_schedule_flip(port); + /* end of service */ cyy_writeb(info, CyRIR, save_xir & 0x3f); cyy_writeb(info, CyCAR, save_car); @@ -924,10 +917,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo, return 0; } /* cyz_issue_cmd */ -static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) +static void cyz_handle_rx(struct cyclades_port *info) { struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; struct cyclades_card *cinfo = info->card; + struct tty_port *port = &info->port; unsigned int char_count; int len; #ifdef BLOCKMOVE @@ -946,80 +940,77 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) else char_count = rx_put - rx_get + rx_bufsize; - if (char_count) { + if (!char_count) + return; + #ifdef CY_ENABLE_MONITORING - info->mon.int_count++; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; + info->mon.int_count++; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; #endif - if (tty == NULL) { - /* flush received characters */ - new_rx_get = (new_rx_get + char_count) & - (rx_bufsize - 1); - info->rflush_count++; - } else { + #ifdef BLOCKMOVE - /* we'd like to use memcpy(t, f, n) and memset(s, c, count) - for performance, but because of buffer boundaries, there - may be several steps to the operation */ - while (1) { - len = tty_prepare_flip_string(tty, &buf, - char_count); - if (!len) - break; + /* we'd like to use memcpy(t, f, n) and memset(s, c, count) + for performance, but because of buffer boundaries, there + may be several steps to the operation */ + while (1) { + len = tty_prepare_flip_string(port, &buf, + char_count); + if (!len) + break; - len = min_t(unsigned int, min(len, char_count), - rx_bufsize - new_rx_get); + len = min_t(unsigned int, min(len, char_count), + rx_bufsize - new_rx_get); - memcpy_fromio(buf, cinfo->base_addr + - rx_bufaddr + new_rx_get, len); + memcpy_fromio(buf, cinfo->base_addr + + rx_bufaddr + new_rx_get, len); - new_rx_get = (new_rx_get + len) & - (rx_bufsize - 1); - char_count -= len; - info->icount.rx += len; - info->idle_stats.recv_bytes += len; - } + new_rx_get = (new_rx_get + len) & + (rx_bufsize - 1); + char_count -= len; + info->icount.rx += len; + info->idle_stats.recv_bytes += len; + } #else - len = tty_buffer_request_room(tty, char_count); - while (len--) { - data = readb(cinfo->base_addr + rx_bufaddr + - new_rx_get); - new_rx_get = (new_rx_get + 1) & - (rx_bufsize - 1); - tty_insert_flip_char(tty, data, TTY_NORMAL); - info->idle_stats.recv_bytes++; - info->icount.rx++; - } + len = tty_buffer_request_room(port, char_count); + while (len--) { + data = readb(cinfo->base_addr + rx_bufaddr + + new_rx_get); + new_rx_get = (new_rx_get + 1) & + (rx_bufsize - 1); + tty_insert_flip_char(port, data, TTY_NORMAL); + info->idle_stats.recv_bytes++; + info->icount.rx++; + } #endif #ifdef CONFIG_CYZ_INTR - /* Recalculate the number of chars in the RX buffer and issue - a cmd in case it's higher than the RX high water mark */ - rx_put = readl(&buf_ctrl->rx_put); - if (rx_put >= rx_get) - char_count = rx_put - rx_get; - else - char_count = rx_put - rx_get + rx_bufsize; - if (char_count >= readl(&buf_ctrl->rx_threshold) && - !timer_pending(&cyz_rx_full_timer[ - info->line])) - mod_timer(&cyz_rx_full_timer[info->line], - jiffies + 1); + /* Recalculate the number of chars in the RX buffer and issue + a cmd in case it's higher than the RX high water mark */ + rx_put = readl(&buf_ctrl->rx_put); + if (rx_put >= rx_get) + char_count = rx_put - rx_get; + else + char_count = rx_put - rx_get + rx_bufsize; + if (char_count >= readl(&buf_ctrl->rx_threshold) && + !timer_pending(&cyz_rx_full_timer[ + info->line])) + mod_timer(&cyz_rx_full_timer[info->line], + jiffies + 1); #endif - info->idle_stats.recv_idle = jiffies; - tty_schedule_flip(tty); - } - /* Update rx_get */ - cy_writel(&buf_ctrl->rx_get, new_rx_get); - } + info->idle_stats.recv_idle = jiffies; + tty_schedule_flip(&info->port); + + /* Update rx_get */ + cy_writel(&buf_ctrl->rx_get, new_rx_get); } -static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) +static void cyz_handle_tx(struct cyclades_port *info) { struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; struct cyclades_card *cinfo = info->card; + struct tty_struct *tty; u8 data; unsigned int char_count; #ifdef BLOCKMOVE @@ -1039,63 +1030,63 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) else char_count = tx_get - tx_put - 1; - if (char_count) { - - if (tty == NULL) - goto ztxdone; + if (!char_count) + return; + + tty = tty_port_tty_get(&info->port); + if (tty == NULL) + goto ztxdone; - if (info->x_char) { /* send special char */ - data = info->x_char; + if (info->x_char) { /* send special char */ + data = info->x_char; - cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); - tx_put = (tx_put + 1) & (tx_bufsize - 1); - info->x_char = 0; - char_count--; - info->icount.tx++; - } + cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); + tx_put = (tx_put + 1) & (tx_bufsize - 1); + info->x_char = 0; + char_count--; + info->icount.tx++; + } #ifdef BLOCKMOVE - while (0 < (small_count = min_t(unsigned int, - tx_bufsize - tx_put, min_t(unsigned int, - (SERIAL_XMIT_SIZE - info->xmit_tail), - min_t(unsigned int, info->xmit_cnt, - char_count))))) { - - memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + - tx_put), - &info->port.xmit_buf[info->xmit_tail], - small_count); - - tx_put = (tx_put + small_count) & (tx_bufsize - 1); - char_count -= small_count; - info->icount.tx += small_count; - info->xmit_cnt -= small_count; - info->xmit_tail = (info->xmit_tail + small_count) & - (SERIAL_XMIT_SIZE - 1); - } + while (0 < (small_count = min_t(unsigned int, + tx_bufsize - tx_put, min_t(unsigned int, + (SERIAL_XMIT_SIZE - info->xmit_tail), + min_t(unsigned int, info->xmit_cnt, + char_count))))) { + + memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put), + &info->port.xmit_buf[info->xmit_tail], + small_count); + + tx_put = (tx_put + small_count) & (tx_bufsize - 1); + char_count -= small_count; + info->icount.tx += small_count; + info->xmit_cnt -= small_count; + info->xmit_tail = (info->xmit_tail + small_count) & + (SERIAL_XMIT_SIZE - 1); + } #else - while (info->xmit_cnt && char_count) { - data = info->port.xmit_buf[info->xmit_tail]; - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - - cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); - tx_put = (tx_put + 1) & (tx_bufsize - 1); - char_count--; - info->icount.tx++; - } + while (info->xmit_cnt && char_count) { + data = info->port.xmit_buf[info->xmit_tail]; + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) & + (SERIAL_XMIT_SIZE - 1); + + cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); + tx_put = (tx_put + 1) & (tx_bufsize - 1); + char_count--; + info->icount.tx++; + } #endif - tty_wakeup(tty); + tty_wakeup(tty); + tty_kref_put(tty); ztxdone: - /* Update tx_put */ - cy_writel(&buf_ctrl->tx_put, tx_put); - } + /* Update tx_put */ + cy_writel(&buf_ctrl->tx_put, tx_put); } static void cyz_handle_cmd(struct cyclades_card *cinfo) { struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - struct tty_struct *tty; struct cyclades_port *info; __u32 channel, param, fw_ver; __u8 cmd; @@ -1108,23 +1099,20 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) special_count = 0; delta_count = 0; info = &cinfo->ports[channel]; - tty = tty_port_tty_get(&info->port); - if (tty == NULL) - continue; switch (cmd) { case C_CM_PR_ERROR: - tty_insert_flip_char(tty, 0, TTY_PARITY); + tty_insert_flip_char(&info->port, 0, TTY_PARITY); info->icount.rx++; special_count++; break; case C_CM_FR_ERROR: - tty_insert_flip_char(tty, 0, TTY_FRAME); + tty_insert_flip_char(&info->port, 0, TTY_FRAME); info->icount.rx++; special_count++; break; case C_CM_RXBRK: - tty_insert_flip_char(tty, 0, TTY_BREAK); + tty_insert_flip_char(&info->port, 0, TTY_BREAK); info->icount.rx++; special_count++; break; @@ -1136,8 +1124,14 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) readl(&info->u.cyz.ch_ctrl->rs_status); if (dcd & C_RS_DCD) wake_up_interruptible(&info->port.open_wait); - else - tty_hangup(tty); + else { + struct tty_struct *tty; + tty = tty_port_tty_get(&info->port); + if (tty) { + tty_hangup(tty); + tty_kref_put(tty); + } + } } break; case C_CM_MCTS: @@ -1166,7 +1160,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " "port %ld\n", info->card, channel); #endif - cyz_handle_rx(info, tty); + cyz_handle_rx(info); break; case C_CM_TXBEMPTY: case C_CM_TXLOWWM: @@ -1176,7 +1170,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " "port %ld\n", info->card, channel); #endif - cyz_handle_tx(info, tty); + cyz_handle_tx(info); break; #endif /* CONFIG_CYZ_INTR */ case C_CM_FATAL: @@ -1188,8 +1182,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) if (delta_count) wake_up_interruptible(&info->port.delta_msr_wait); if (special_count) - tty_schedule_flip(tty); - tty_kref_put(tty); + tty_schedule_flip(&info->port); } } @@ -1255,17 +1248,11 @@ static void cyz_poll(unsigned long arg) cyz_handle_cmd(cinfo); for (port = 0; port < cinfo->nports; port++) { - struct tty_struct *tty; - info = &cinfo->ports[port]; - tty = tty_port_tty_get(&info->port); - /* OK to pass NULL to the handle functions below. - They need to drop the data in that case. */ if (!info->throttle) - cyz_handle_rx(info, tty); - cyz_handle_tx(info, tty); - tty_kref_put(tty); + cyz_handle_rx(info); + cyz_handle_tx(info); } /* poll every 'cyz_polling_cycle' period */ expires = jiffies + cyz_polling_cycle; |