diff options
Diffstat (limited to 'drivers/char')
31 files changed, 536 insertions, 560 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 977a74e16efb..d6fcd0a36f9f 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -80,7 +80,7 @@ config SERIAL_NONSTANDARD config COMPUTONE tristate "Computone IntelliPort Plus serial support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD ---help--- This driver supports the entire family of Intelliport II/Plus controllers with the exception of the MicroChannel controllers and @@ -153,7 +153,7 @@ config DIGIEPCA config ESPSERIAL tristate "Hayes ESP serial port support" - depends on SERIAL_NONSTANDARD && ISA && BROKEN_ON_SMP && ISA_DMA_API + depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API help This is a driver which supports Hayes ESP serial ports. Both single port cards and multiport cards are supported. Make sure to read @@ -166,7 +166,7 @@ config ESPSERIAL config MOXA_INTELLIO tristate "Moxa Intellio support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD help Say Y here if you have a Moxa Intellio multiport serial card. diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 10c81ecdace8..869518e4035f 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -265,8 +265,9 @@ static _INLINE_ void receive_chars(struct async_struct *info) int status; int serdatr; struct tty_struct *tty = info->tty; - unsigned char ch; + unsigned char ch, flag; struct async_icount *icount; + int oe = 0; icount = &info->state->icount; @@ -282,15 +283,12 @@ static _INLINE_ void receive_chars(struct async_struct *info) status |= UART_LSR_OE; ch = serdatr & 0xff; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; - *tty->flip.char_buf_ptr = ch; icount->rx++; #ifdef SERIAL_DEBUG_INTR printk("DR%02x:%02x...", ch, status); #endif - *tty->flip.flag_buf_ptr = 0; + flag = TTY_NORMAL; /* * We don't handle parity or frame errors - but I have left @@ -319,7 +317,7 @@ static _INLINE_ void receive_chars(struct async_struct *info) * should be ignored. */ if (status & info->ignore_status_mask) - goto ignore_char; + goto out; status &= info->read_status_mask; @@ -327,33 +325,28 @@ static _INLINE_ void receive_chars(struct async_struct *info) #ifdef SERIAL_DEBUG_INTR printk("handling break...."); #endif - *tty->flip.flag_buf_ptr = TTY_BREAK; + flag = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (status & UART_LSR_PE) - *tty->flip.flag_buf_ptr = TTY_PARITY; + flag = TTY_PARITY; else if (status & UART_LSR_FE) - *tty->flip.flag_buf_ptr = TTY_FRAME; + flag = TTY_FRAME; if (status & UART_LSR_OE) { /* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } + oe = 1; } } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - ignore_char: - + tty_insert_flip_char(tty, ch, flag); + if (oe == 1) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_flip_buffer_push(tty); +out: + return; } static _INLINE_ void transmit_chars(struct async_struct *info) diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c8e7daecad72..39c61a71176e 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -641,6 +641,7 @@ static char rcsid[] = #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/major.h> #include <linux/string.h> @@ -1086,7 +1087,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) int had_work; int mdm_change; int mdm_status; - + int len; if((cinfo = (struct cyclades_card *)dev_id) == 0){ #ifdef CY_DEBUG_INTERRUPTS printk("cyy_interrupt: spurious interrupt %d\n\r", irq); @@ -1163,63 +1164,43 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) info->icount.rx++; continue; } - if (tty->flip.count < TTY_FLIPBUF_SIZE){ - tty->flip.count++; + if (tty_buffer_request_room(tty, 1)) { if (data & info->read_status_mask){ if(data & CyBREAK){ - *tty->flip.flag_buf_ptr++ = - TTY_BREAK; - *tty->flip.char_buf_ptr++ = - cy_readb(base_addr+(CyRDSR<<index)); + tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK); info->icount.rx++; if (info->flags & ASYNC_SAK){ do_SAK(tty); } }else if(data & CyFRAME){ - *tty->flip.flag_buf_ptr++ = - TTY_FRAME; - *tty->flip.char_buf_ptr++ = - cy_readb(base_addr+(CyRDSR<<index)); + tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); info->icount.rx++; info->idle_stats.frame_errs++; }else if(data & CyPARITY){ - *tty->flip.flag_buf_ptr++ = - TTY_PARITY; - *tty->flip.char_buf_ptr++ = - cy_readb(base_addr+(CyRDSR<<index)); + /* Pieces of seven... */ + tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY); info->icount.rx++; info->idle_stats.parity_errs++; }else if(data & CyOVERRUN){ - *tty->flip.flag_buf_ptr++ = - TTY_OVERRUN; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); info->icount.rx++; /* If the flip buffer itself is overflowing, we still lose the next incoming character. */ - if(tty->flip.count - < TTY_FLIPBUF_SIZE){ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = - TTY_NORMAL; - *tty->flip.char_buf_ptr++ = - cy_readb(base_addr+(CyRDSR<<index)); - info->icount.rx++; - } + tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); + info->icount.rx++; info->idle_stats.overruns++; /* These two conditions may imply */ /* a normal read should be done. */ /* }else if(data & CyTIMEOUT){ */ /* }else if(data & CySPECHAR){ */ - }else{ - *tty->flip.flag_buf_ptr++ = 0; - *tty->flip.char_buf_ptr++ = 0; - info->icount.rx++; + }else { + tty_insert_flip_char(tty, 0, TTY_NORMAL); + info->icount.rx++; } }else{ - *tty->flip.flag_buf_ptr++ = 0; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_NORMAL); info->icount.rx++; } }else{ @@ -1240,14 +1221,10 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) info->mon.char_max = char_count; info->mon.char_last = char_count; #endif - while(char_count--){ - if (tty->flip.count >= TTY_FLIPBUF_SIZE){ - break; - } - tty->flip.count++; + len = tty_buffer_request_room(tty, char_count); + while(len--){ data = cy_readb(base_addr+(CyRDSR<<index)); - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = data; + tty_insert_flip_char(tty, data, TTY_NORMAL); info->idle_stats.recv_bytes++; info->icount.rx++; #ifdef CY_16Y_HACK @@ -1256,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) } info->idle_stats.recv_idle = jiffies; } - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); } /* end of service */ cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); @@ -1551,6 +1528,7 @@ cyz_handle_rx(struct cyclades_port *info, struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; volatile int char_count; + int len; #ifdef BLOCKMOVE int small_count; #else @@ -1606,18 +1584,11 @@ cyz_handle_rx(struct cyclades_port *info, tty->flip.count += small_count; } #else - while(char_count--){ - if (tty->flip.count >= N_TTY_BUF_SIZE - tty->read_cnt) - break; - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - + len = tty_buffer_request_room(tty, char_count); + while(len--){ data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get); new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1); - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = data; + tty_insert_flip_char(tty, data, TTY_NORMAL); info->idle_stats.recv_bytes++; info->icount.rx++; } @@ -1635,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info, } #endif info->idle_stats.recv_idle = jiffies; - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); } /* Update rx_get */ cy_writel(&buf_ctrl->rx_get, new_rx_get); @@ -1763,23 +1734,17 @@ cyz_handle_cmd(struct cyclades_card *cinfo) switch(cmd) { case C_CM_PR_ERROR: - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_PARITY; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_PARITY); info->icount.rx++; special_count++; break; case C_CM_FR_ERROR: - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_FRAME; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_FRAME); info->icount.rx++; special_count++; break; case C_CM_RXBRK: - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_BREAK); info->icount.rx++; special_count++; break; @@ -1844,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo) if(delta_count) cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); if(special_count) - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); } } diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 407708a001e4..765c5c108bf4 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1786,9 +1786,7 @@ static void doevent(int crd) if (tty) { /* Begin if valid tty */ if (event & BREAK_IND) { /* Begin if BREAK_IND */ /* A break has been indicated */ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_BREAK); tty_schedule_flip(tty); } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */ if (ch->statusflags & LOWWAIT) @@ -2124,7 +2122,6 @@ static void receive_data(struct channel *ch) int dataToRead, wrapgap, bytesAvailable; unsigned int tail, head; unsigned int wrapmask; - int rc; /* --------------------------------------------------------------- This routine is called by doint when a receive data event @@ -2162,16 +2159,15 @@ static void receive_data(struct channel *ch) return; } - if (tty->flip.count == TTY_FLIPBUF_SIZE) + if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0) return; if (readb(&bc->orun)) { writeb(0, &bc->orun); printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name); + tty_insert_flip_char(tty, 0, TTY_OVERRUN); } rxwinon(ch); - rptr = tty->flip.char_buf_ptr; - rc = tty->flip.count; while (bytesAvailable > 0) { /* Begin while there is data on the card */ wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail; /* --------------------------------------------------------------- @@ -2183,8 +2179,7 @@ static void receive_data(struct channel *ch) /* -------------------------------------------------------------- Make sure we don't overflow the buffer ----------------------------------------------------------------- */ - if ((rc + dataToRead) > TTY_FLIPBUF_SIZE) - dataToRead = TTY_FLIPBUF_SIZE - rc; + dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead); if (dataToRead == 0) break; /* --------------------------------------------------------------- @@ -2192,13 +2187,9 @@ static void receive_data(struct channel *ch) for translation if necessary. ------------------------------------------------------------------ */ memcpy_fromio(rptr, ch->rxptr + tail, dataToRead); - rc += dataToRead; - rptr += dataToRead; tail = (tail + dataToRead) & wrapmask; bytesAvailable -= dataToRead; } /* End while there is data on the card */ - tty->flip.count = rc; - tty->flip.char_buf_ptr = rptr; globalwinon(ch); writew(tail, &bc->rout); /* Must be called with global data */ diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 9f53d2fcc360..e469f641c728 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -345,26 +345,22 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) for (i = 0; i < num_bytes; i++) { if (!(err_buf->data[i] & status_mask)) { - *(tty->flip.char_buf_ptr++) = pio_buf->data[i]; + int flag = 0; if (err_buf->data[i] & 0x04) { - *(tty->flip.flag_buf_ptr++) = TTY_BREAK; - + flag = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (err_buf->data[i] & 0x02) - *(tty->flip.flag_buf_ptr++) = TTY_FRAME; + flag = TTY_FRAME; else if (err_buf->data[i] & 0x01) - *(tty->flip.flag_buf_ptr++) = TTY_PARITY; - else - *(tty->flip.flag_buf_ptr++) = 0; - - tty->flip.count++; + flag = TTY_PARITY; + tty_insert_flip_char(tty, pio_buf->data[i], flag); } } - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; release_pio_buffer(pio_buf); @@ -397,7 +393,6 @@ static inline void receive_chars_dma_done(struct esp_struct *info, int num_bytes; unsigned long flags; - flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); @@ -408,38 +403,31 @@ static inline void receive_chars_dma_done(struct esp_struct *info, info->icount.rx += num_bytes; - memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes); - tty->flip.char_buf_ptr += num_bytes; - tty->flip.count += num_bytes; - memset(tty->flip.flag_buf_ptr, 0, num_bytes); - tty->flip.flag_buf_ptr += num_bytes; - if (num_bytes > 0) { - tty->flip.flag_buf_ptr--; + tty_insert_flip_string(tty, dma_buffer, num_bytes - 1); status &= (0x1c & info->read_status_mask); + + /* Is the status significant or do we throw the last byte ? */ + if (!(status & info->ignore_status_mask)) { + int statflag = 0; - if (status & info->ignore_status_mask) { - tty->flip.count--; - tty->flip.char_buf_ptr--; - tty->flip.flag_buf_ptr--; - } else if (status & 0x10) { - *tty->flip.flag_buf_ptr = TTY_BREAK; - (info->icount.brk)++; - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (status & 0x08) { - *tty->flip.flag_buf_ptr = TTY_FRAME; - (info->icount.frame)++; - } - else if (status & 0x04) { - *tty->flip.flag_buf_ptr = TTY_PARITY; - (info->icount.parity)++; + if (status & 0x10) { + statflag = TTY_BREAK; + (info->icount.brk)++; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (status & 0x08) { + statflag = TTY_FRAME; + (info->icount.frame)++; + } + else if (status & 0x04) { + statflag = TTY_PARITY; + (info->icount.parity)++; + } + tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag); } - - tty->flip.flag_buf_ptr++; - - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); } if (dma_bytes != num_bytes) { @@ -693,8 +681,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id, num_bytes = serial_in(info, UART_ESI_STAT1) << 8; num_bytes |= serial_in(info, UART_ESI_STAT2); - if (num_bytes > (TTY_FLIPBUF_SIZE - info->tty->flip.count)) - num_bytes = TTY_FLIPBUF_SIZE - info->tty->flip.count; + num_bytes = tty_buffer_request_room(info->tty, num_bytes); if (num_bytes) { if (dma_bytes || diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index f92177634677..1994a92d4733 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -597,9 +597,7 @@ static int hvc_poll(struct hvc_struct *hp) /* Read data if any */ for (;;) { - int count = N_INBUF; - if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) - count = TTY_FLIPBUF_SIZE - tty->flip.count; + int count = tty_buffer_request_room(tty, N_INBUF); /* If flip is full, just reschedule a later read */ if (count == 0) { @@ -635,7 +633,7 @@ static int hvc_poll(struct hvc_struct *hp) tty_insert_flip_char(tty, buf[i], 0); } - if (tty->flip.count) + if (count) tty_schedule_flip(tty); /* diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 53dc77c760fc..831eb4e8d9d3 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -456,12 +456,11 @@ static int hvcs_io(struct hvcs_struct *hvcsd) /* remove the read masks */ hvcsd->todo_mask &= ~(HVCS_READ_MASK); - if ((tty->flip.count + HVCS_BUFF_LEN) < TTY_FLIPBUF_SIZE) { + if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) { got = hvc_get_chars(unit_address, &buf[0], HVCS_BUFF_LEN); - for (i=0;got && i<got;i++) - tty_insert_flip_char(tty, buf[i], TTY_NORMAL); + tty_insert_flip_string(tty, buf, got); } /* Give the TTY time to process the data we just sent. */ @@ -469,10 +468,9 @@ static int hvcs_io(struct hvcs_struct *hvcsd) hvcsd->todo_mask |= HVCS_QUICK_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); - if (tty->flip.count) { - /* This is synch because tty->low_latency == 1 */ + /* This is synch because tty->low_latency == 1 */ + if(got) tty_flip_buffer_push(tty); - } if (!got) { /* Do this _after_ the flip_buffer_push */ diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 1bbf507adda5..86033bed5d6c 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -115,6 +115,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/termios.h> #include <linux/fs.h> #include <linux/sched.h> @@ -773,6 +774,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, unsigned short base, header, word_count, count; unsigned char channel; short byte_count; + unsigned char *rp; card = (struct isi_board *) dev_id; @@ -903,14 +905,10 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, break; case 1: /* Received Break !!! */ - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = 0; - tty->flip.count++; + tty_insert_flip_char(tty, 0, TTY_BREAK); if (port->flags & ASYNC_SAK) do_SAK(tty); - schedule_delayed_work(&tty->flip.work, 1); + tty_flip_buffer_push(tty); break; case 2: /* Statistics */ @@ -923,23 +921,19 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, } } else { /* Data Packet */ - count = min_t(unsigned short, byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); + + count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n", count, byte_count); #endif word_count = count >> 1; - insw(base, tty->flip.char_buf_ptr, word_count); - tty->flip.char_buf_ptr += (word_count << 1); + insw(base, rp, word_count); byte_count -= (word_count << 1); if (count & 0x0001) { - *tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff); + tty_insert_flip_char(tty, inw(base) & 0xff, TTY_NORMAL); byte_count -= 2; } - memset(tty->flip.flag_buf_ptr, 0, count); - tty->flip.flag_buf_ptr += count; - tty->flip.count += count; - if (byte_count > 0) { printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n", base, channel+1); @@ -948,7 +942,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, byte_count -= 2; } } - schedule_delayed_work(&tty->flip.work, 1); + tty_flip_buffer_push(tty); } if (card->isa == YES) ClearInterrupt(base); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 24435f8daa68..28c5a3193b81 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -2711,17 +2711,13 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp) stlen = size - tail; } - len = MIN(len, (TTY_FLIPBUF_SIZE - tty->flip.count)); + len = tty_buffer_request_room(tty, len); + /* FIXME : iomap ? */ shbuf = (volatile char *) EBRDGETMEMPTR(brdp, portp->rxoffset); while (len > 0) { stlen = MIN(len, stlen); - memcpy(tty->flip.char_buf_ptr, (char *) (shbuf + tail), stlen); - memset(tty->flip.flag_buf_ptr, 0, stlen); - tty->flip.char_buf_ptr += stlen; - tty->flip.flag_buf_ptr += stlen; - tty->flip.count += stlen; - + tty_insert_flip_string(tty, (char *)(shbuf + tail), stlen); len -= stlen; tail += stlen; if (tail >= size) { @@ -2906,16 +2902,12 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) { if (tty != (struct tty_struct *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = 0; - if (portp->flags & ASYNC_SAK) { - do_SAK(tty); - EBRDENABLE(brdp); - } - tty_schedule_flip(tty); + tty_insert_flip_char(tty, 0, TTY_BREAK); + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + EBRDENABLE(brdp); } + tty_schedule_flip(tty); } } @@ -4940,7 +4932,7 @@ static int stli_portcmdstats(stliport_t *portp) if (portp->tty != (struct tty_struct *) NULL) { if (portp->tty->driver_data == portp) { stli_comstats.ttystate = portp->tty->flags; - stli_comstats.rxbuffered = portp->tty->flip.count; + stli_comstats.rxbuffered = -1 /*portp->tty->flip.count*/; if (portp->tty->termios != (struct termios *) NULL) { stli_comstats.cflags = portp->tty->termios->c_cflag; stli_comstats.iflags = portp->tty->termios->c_iflag; diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 46a3a8ccd65f..5e3ef5522194 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -269,7 +269,7 @@ static int MoxaPortDCDChange(int); static int MoxaPortDCDON(int); static void MoxaPortFlushData(int, int); static int MoxaPortWriteData(int, unsigned char *, int); -static int MoxaPortReadData(int, unsigned char *, int); +static int MoxaPortReadData(int, struct tty_struct *tty); static int MoxaPortTxQueue(int); static int MoxaPortRxQueue(int); static int MoxaPortTxFree(int); @@ -301,6 +301,8 @@ static struct tty_operations moxa_ops = { .tiocmset = moxa_tiocmset, }; +static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED; + #ifdef CONFIG_PCI static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) { @@ -645,10 +647,10 @@ static int moxa_write(struct tty_struct *tty, if (ch == NULL) return (0); port = ch->port; - save_flags(flags); - cli(); + + spin_lock_irqsave(&moxa_lock, flags); len = MoxaPortWriteData(port, (unsigned char *) buf, count); - restore_flags(flags); + spin_unlock_irqrestore(&moxa_lock, flags); /********************************************* if ( !(ch->statusflags & LOWWAIT) && @@ -723,11 +725,10 @@ static void moxa_put_char(struct tty_struct *tty, unsigned char c) if (ch == NULL) return; port = ch->port; - save_flags(flags); - cli(); + spin_lock_irqsave(&moxa_lock, flags); moxaXmitBuff[0] = c; MoxaPortWriteData(port, moxaXmitBuff, 1); - restore_flags(flags); + spin_unlock_irqrestore(&moxa_lock, flags); /************************************************ if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) *************************************************/ @@ -1030,12 +1031,12 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp, printk("block_til_ready before block: ttys%d, count = %d\n", ch->line, ch->count); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&moxa_lock, flags); if (!tty_hung_up_p(filp)) ch->count--; - restore_flags(flags); ch->blocked_open++; + spin_unlock_irqrestore(&moxa_lock, flags); + while (1) { set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -1062,17 +1063,21 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp, } set_current_state(TASK_RUNNING); remove_wait_queue(&ch->open_wait, &wait); + + spin_lock_irqsave(&moxa_lock, flags); if (!tty_hung_up_p(filp)) ch->count++; ch->blocked_open--; + spin_unlock_irqrestore(&moxa_lock, flags); #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", ch->line, ch->count); #endif if (retval) return (retval); + /* FIXME: review to see if we need to use set_bit on these */ ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return (0); + return 0; } static void setup_empty_event(struct tty_struct *tty) @@ -1080,15 +1085,14 @@ static void setup_empty_event(struct tty_struct *tty) struct moxa_str *ch = tty->driver_data; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&moxa_lock, flags); ch->statusflags |= EMPTYWAIT; moxaEmptyTimer_on[ch->port] = 0; del_timer(&moxaEmptyTimer[ch->port]); moxaEmptyTimer[ch->port].expires = jiffies + HZ; moxaEmptyTimer_on[ch->port] = 1; add_timer(&moxaEmptyTimer[ch->port]); - restore_flags(flags); + spin_unlock_irqrestore(&moxa_lock, flags); } static void check_xmit_empty(unsigned long data) @@ -1135,8 +1139,6 @@ static void receive_data(struct moxa_str *ch) { struct tty_struct *tp; struct termios *ts; - int i, count, rc, space; - unsigned char *charptr, *flagptr; unsigned long flags; ts = NULL; @@ -1150,24 +1152,10 @@ static void receive_data(struct moxa_str *ch) MoxaPortFlushData(ch->port, 0); return; } - space = TTY_FLIPBUF_SIZE - tp->flip.count; - if (space <= 0) - return; - charptr = tp->flip.char_buf_ptr; - flagptr = tp->flip.flag_buf_ptr; - rc = tp->flip.count; - save_flags(flags); - cli(); - count = MoxaPortReadData(ch->port, charptr, space); - restore_flags(flags); - for (i = 0; i < count; i++) - *flagptr++ = 0; - charptr += count; - rc += count; - tp->flip.count = rc; - tp->flip.char_buf_ptr = charptr; - tp->flip.flag_buf_ptr = flagptr; - tty_schedule_flip(ch->tty); + spin_lock_irqsave(&moxa_lock, flags); + MoxaPortReadData(ch->port, tp); + spin_unlock_irqrestore(&moxa_lock, flags); + tty_schedule_flip(tp); } #define Magic_code 0x404 @@ -1774,7 +1762,7 @@ int MoxaPortsOfCard(int cardno) * 14. MoxaPortDCDON(int port); * * 15. MoxaPortFlushData(int port, int mode); * * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); * - * 17. MoxaPortReadData(int port, unsigned char * buffer, int length); * + * 17. MoxaPortReadData(int port, struct tty_struct *tty); * * 18. MoxaPortTxBufSize(int port); * * 19. MoxaPortRxBufSize(int port); * * 20. MoxaPortTxQueue(int port); * @@ -2003,10 +1991,9 @@ int MoxaPortsOfCard(int cardno) * * Function 21: Read data. * Syntax: - * int MoxaPortReadData(int port, unsigned char * buffer, int length); + * int MoxaPortReadData(int port, struct tty_struct *tty); * int port : port number (0 - 127) - * unsigned char * buffer : pointer to read data buffer. - * int length : read data buffer length + * struct tty_struct *tty : tty for data * * return: 0 - length : real read data length * @@ -2504,7 +2491,7 @@ int MoxaPortWriteData(int port, unsigned char * buffer, int len) return (total); } -int MoxaPortReadData(int port, unsigned char * buffer, int space) +int MoxaPortReadData(int port, struct tty_struct *tty) { register ushort head, pageofs; int i, count, cnt, len, total, remain; @@ -2522,9 +2509,9 @@ int MoxaPortReadData(int port, unsigned char * buffer, int space) count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1); if (count == 0) - return (0); + return 0; - total = (space > count) ? count : space; + total = count; remain = count - total; moxaLog.rxcnt[port] += total; count = total; @@ -2539,7 +2526,7 @@ int MoxaPortReadData(int port, unsigned char * buffer, int space) len = (count > len) ? len : count; ofs = baseAddr + DynPage_addr + bufhead + head; for (i = 0; i < len; i++) - *buffer++ = readb(ofs + i); + tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL); head = (head + len) & rx_mask; count -= len; } @@ -2556,7 +2543,7 @@ int MoxaPortReadData(int port, unsigned char * buffer, int space) writew(pageno, baseAddr + Control_reg); ofs = baseAddr + DynPage_addr + pageofs; for (i = 0; i < cnt; i++) - *buffer++ = readb(ofs + i); + tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL); if (count == 0) { writew((head + len) & rx_mask, ofsAddr + RXrptr); break; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 51bb2a3cf8b3..ea725a9964e2 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -1982,7 +1982,7 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) spin_lock_irqsave(&info->slock, flags); - recv_room = tty->ldisc.receive_room(tty); + recv_room = tty->receive_room; if ((recv_room == 0) && (!info->ldisc_stop_rx)) { //mxser_throttle(tty); mxser_stoprx(tty); diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index a133a62f3d55..70f487dd7b8d 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -212,7 +212,6 @@ static struct tty_ldisc n_hdlc_ldisc = { .ioctl = n_hdlc_tty_ioctl, .poll = n_hdlc_tty_poll, .receive_buf = n_hdlc_tty_receive, - .receive_room = n_hdlc_tty_room, .write_wakeup = n_hdlc_tty_wakeup, }; @@ -337,6 +336,7 @@ static int n_hdlc_tty_open (struct tty_struct *tty) tty->disc_data = n_hdlc; n_hdlc->tty = tty; + tty->receive_room = 65536; #if defined(TTY_NO_WRITE_SPLIT) /* change tty_io write() to not split large writes into 8K chunks */ @@ -478,22 +478,6 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) } /* end of n_hdlc_tty_wakeup() */ /** - * n_hdlc_tty_room - Return the amount of space left in the receiver's buffer - * @tty - pointer to associated tty instance data - * - * Callback function from tty driver. Return the amount of space left in the - * receiver's buffer to decide if remote transmitter is to be throttled. - */ -static int n_hdlc_tty_room(struct tty_struct *tty) -{ - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__); - /* always return a larger number to prevent */ - /* throttling of remote transmitter. */ - return 65536; -} /* end of n_hdlc_tty_root() */ - -/** * n_hdlc_tty_receive - Called by tty driver when receive data is available * @tty - pointer to tty instance data * @data - pointer to received data diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 853c98cee64f..c48de09d68f0 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -147,7 +147,6 @@ static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, struct poll_table_struct *wait); static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count); -static int r3964_receive_room(struct tty_struct *tty); static struct tty_ldisc tty_ldisc_N_R3964 = { .owner = THIS_MODULE, @@ -161,7 +160,6 @@ static struct tty_ldisc tty_ldisc_N_R3964 = { .set_termios = r3964_set_termios, .poll = r3964_poll, .receive_buf = r3964_receive_buf, - .receive_room = r3964_receive_room, }; @@ -1119,6 +1117,7 @@ static int r3964_open(struct tty_struct *tty) pInfo->nRetry = 0; tty->disc_data = pInfo; + tty->receive_room = 65536; init_timer(&pInfo->tmr); pInfo->tmr.data = (unsigned long)pInfo; @@ -1405,12 +1404,5 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, } } -static int r3964_receive_room(struct tty_struct *tty) -{ - TRACE_L("receive_room"); - return -1; -} - - MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_R3964); diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index c556f4d3ccd7..ccad7ae94541 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -78,7 +78,32 @@ static inline void free_buf(unsigned char *buf) free_page((unsigned long) buf); } -static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) +/** + * n_tty_set__room - receive space + * @tty: terminal + * + * Called by the driver to find out how much data it is + * permitted to feed to the line discipline without any being lost + * and thus to manage flow control. Not serialized. Answers for the + * "instant". + */ + +static void n_tty_set_room(struct tty_struct *tty) +{ + int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + + /* + * If we are doing input canonicalization, and there are no + * pending newlines, let characters through without limit, so + * that erase characters will be handled. Other excess + * characters will be beeped. + */ + if (left <= 0) + left = tty->icanon && !tty->canon_data; + tty->receive_room = left; +} + +static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) { if (tty->read_cnt < N_TTY_BUF_SIZE) { tty->read_buf[tty->read_head] = c; @@ -87,7 +112,7 @@ static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) } } -static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) +static void put_tty_queue(unsigned char c, struct tty_struct *tty) { unsigned long flags; /* @@ -136,6 +161,7 @@ static void reset_buffer_flags(struct tty_struct *tty) spin_unlock_irqrestore(&tty->read_lock, flags); tty->canon_head = tty->canon_data = tty->erasing = 0; memset(&tty->read_flags, 0, sizeof tty->read_flags); + n_tty_set_room(tty); check_unthrottle(tty); } @@ -838,30 +864,6 @@ send_signal: put_tty_queue(c, tty); } -/** - * n_tty_receive_room - receive space - * @tty: terminal - * - * Called by the driver to find out how much data it is - * permitted to feed to the line discipline without any being lost - * and thus to manage flow control. Not serialized. Answers for the - * "instant". - */ - -static int n_tty_receive_room(struct tty_struct *tty) -{ - int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; - - /* - * If we are doing input canonicalization, and there are no - * pending newlines, let characters through without limit, so - * that erase characters will be handled. Other excess - * characters will be beeped. - */ - if (left <= 0) - left = tty->icanon && !tty->canon_data; - return left; -} /** * n_tty_write_wakeup - asynchronous I/O notifier @@ -953,6 +955,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, tty->driver->flush_chars(tty); } + n_tty_set_room(tty); + if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) @@ -964,7 +968,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, * mode. We don't want to throttle the driver if we're in * canonical mode and don't have a newline yet! */ - if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) { + if (tty->receive_room < TTY_THRESHOLD_THROTTLE) { /* check TTY_THROTTLED first so it indicates our state */ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && tty->driver->throttle) @@ -999,6 +1003,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { tty->raw = 1; tty->real_raw = 1; + n_tty_set_room(tty); return; } if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || @@ -1051,6 +1056,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) else tty->real_raw = 0; } + n_tty_set_room(tty); } /** @@ -1130,7 +1136,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * */ -static inline int copy_from_read_buf(struct tty_struct *tty, +static int copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr) @@ -1308,6 +1314,7 @@ do_it_again: retval = -ERESTARTSYS; break; } + n_tty_set_room(tty); clear_bit(TTY_DONT_FLIP, &tty->flags); timeout = schedule_timeout(timeout); set_bit(TTY_DONT_FLIP, &tty->flags); @@ -1401,6 +1408,8 @@ do_it_again: } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) goto do_it_again; + n_tty_set_room(tty); + return retval; } @@ -1553,7 +1562,6 @@ struct tty_ldisc tty_ldisc_N_TTY = { normal_poll, /* poll */ NULL, /* hangup */ n_tty_receive_buf, /* receive_buf */ - n_tty_receive_room, /* receive_room */ n_tty_write_wakeup /* write_wakeup */ }; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 9fb10c9fec88..8a8ca32822ba 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1007,8 +1007,9 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) static void rx_ready_async(MGSLPC_INFO *info, int tcd) { - unsigned char data, status; + unsigned char data, status, flag; int fifo_count; + int work = 0; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; @@ -1023,20 +1024,16 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd) fifo_count = 32; } else fifo_count = 32; - + + tty_buffer_request_room(tty, fifo_count); /* Flush received async data to receive data buffer. */ while (fifo_count) { data = read_reg(info, CHA + RXFIFO); status = read_reg(info, CHA + RXFIFO); fifo_count -= 2; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - - *tty->flip.char_buf_ptr = data; icount->rx++; - - *tty->flip.flag_buf_ptr = 0; + flag = TTY_NORMAL; // if no frameing/crc error then save data // BIT7:parity error @@ -1055,26 +1052,23 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd) status &= info->read_status_mask; if (status & BIT7) - *tty->flip.flag_buf_ptr = TTY_PARITY; + flag = TTY_PARITY; else if (status & BIT6) - *tty->flip.flag_buf_ptr = TTY_FRAME; + flag = TTY_FRAME; } - - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + work += tty_insert_flip_char(tty, data, flag); } issue_command(info, CHA, CMD_RXFIFO); if (debug_level >= DEBUG_LEVEL_ISR) { - printk("%s(%d):rx_ready_async count=%d\n", - __FILE__,__LINE__,tty->flip.count); + printk("%s(%d):rx_ready_async", + __FILE__,__LINE__); printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", __FILE__,__LINE__,icount->rx,icount->brk, icount->parity,icount->frame,icount->overrun); } - if (tty->flip.count) + if (work) tty_flip_buffer_push(tty); } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 49f3997fd251..9b5a2c0e7008 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -111,7 +111,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun if (!to || tty->stopped) return 0; - c = to->ldisc.receive_room(to); + c = to->receive_room; if (c > count) c = count; to->ldisc.receive_buf(to, buf, NULL, c); @@ -126,7 +126,7 @@ static int pty_write_room(struct tty_struct *tty) if (!to || tty->stopped) return 0; - return to->ldisc.receive_room(to); + return to->receive_room; } /* diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index e42e7b50bf6b..ddda9c14e059 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -38,6 +38,7 @@ static char *_riointr_c_sccs_ = "@(#)riointr.c 1.2"; #include <linux/slab.h> #include <linux/errno.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <asm/io.h> #include <asm/system.h> #include <asm/string.h> @@ -560,6 +561,7 @@ struct Port * PortP; struct PKT *PacketP; register uint DataCnt; uchar * ptr; + unsigned char *buf; int copied =0; static int intCount, RxIntCnt; @@ -657,8 +659,7 @@ struct Port * PortP; ** and available space. */ - transCount = min_t(unsigned int, PacketP->len & PKT_LEN_MASK, - TTY_FLIPBUF_SIZE - TtyP->flip.count); + transCount = tty_buffer_request_room(TtyP, PacketP->len & PKT_LEN_MASK); rio_dprintk (RIO_DEBUG_REC, "port %d: Copy %d bytes\n", PortP->PortNum, transCount); /* @@ -678,9 +679,8 @@ struct Port * PortP; #endif ptr = (uchar *) PacketP->data + PortP->RxDataStart; - rio_memcpy_fromio (TtyP->flip.char_buf_ptr, ptr, transCount); - memset(TtyP->flip.flag_buf_ptr, TTY_NORMAL, transCount); - + tty_prepare_flip_string(TtyP, &buf, transCount); + rio_memcpy_fromio (buf, ptr, transCount); #ifdef STATS /* ** keep a count for statistical purposes @@ -690,9 +690,6 @@ struct Port * PortP; PortP->RxDataStart += transCount; PacketP->len -= transCount; copied += transCount; - TtyP->flip.count += transCount; - TtyP->flip.char_buf_ptr += transCount; - TtyP->flip.flag_buf_ptr += transCount; #ifdef ___DEBUG_IT___ diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 5dae32521620..050e70ee5920 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -46,6 +46,7 @@ #include <linux/major.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/tty_flip.h> #include <asm/uaccess.h> @@ -354,28 +355,17 @@ static inline void rc_receive_exc(struct riscom_board const * bp) struct riscom_port *port; struct tty_struct *tty; unsigned char status; - unsigned char ch; + unsigned char ch, flag; if (!(port = rc_get_port(bp, "Receive"))) return; tty = port->tty; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { - printk(KERN_WARNING "rc%d: port %d: Working around flip " - "buffer overflow.\n", - board_No(bp), port_No(port)); - return; - } #ifdef RC_REPORT_OVERRUN status = rc_in(bp, CD180_RCSR); - if (status & RCSR_OE) { + if (status & RCSR_OE) port->overrun++; -#if 0 - printk(KERN_ERR "rc%d: port %d: Overrun. Total %ld overruns\n", - board_No(bp), port_No(port), port->overrun); -#endif - } status &= port->mark_mask; #else status = rc_in(bp, CD180_RCSR) & port->mark_mask; @@ -393,25 +383,24 @@ static inline void rc_receive_exc(struct riscom_board const * bp) } else if (status & RCSR_BREAK) { printk(KERN_INFO "rc%d: port %d: Handling break...\n", board_No(bp), port_No(port)); - *tty->flip.flag_buf_ptr++ = TTY_BREAK; + flag = TTY_BREAK; if (port->flags & ASYNC_SAK) do_SAK(tty); } else if (status & RCSR_PE) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; + flag = TTY_PARITY; else if (status & RCSR_FE) - *tty->flip.flag_buf_ptr++ = TTY_FRAME; + flag = TTY_FRAME; else if (status & RCSR_OE) - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + flag = TTY_OVERRUN; else - *tty->flip.flag_buf_ptr++ = 0; + flag = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - schedule_delayed_work(&tty->flip.work, 1); + tty_insert_flip_char(tty, ch, flag); + tty_flip_buffer_push(tty); } static inline void rc_receive(struct riscom_board const * bp) @@ -432,17 +421,15 @@ static inline void rc_receive(struct riscom_board const * bp) #endif while (count--) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + if (tty_buffer_request_room(tty, 1) == 0) { printk(KERN_WARNING "rc%d: port %d: Working around " "flip buffer overflow.\n", board_No(bp), port_No(port)); break; } - *tty->flip.char_buf_ptr++ = rc_in(bp, CD180_RDR); - *tty->flip.flag_buf_ptr++ = 0; - tty->flip.count++; + tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL); } - schedule_delayed_work(&tty->flip.work, 1); + tty_flip_buffer_push(tty); } static inline void rc_transmit(struct riscom_board const * bp) diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index d3bc731fbb27..0949dcef0697 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -325,19 +325,16 @@ static void rp_do_receive(struct r_port *info, { unsigned int CharNStat; int ToRecv, wRecv, space = 0, count; - unsigned char *cbuf; - char *fbuf; + unsigned char *cbuf, *chead; + char *fbuf, *fhead; struct tty_ldisc *ld; ld = tty_ldisc_ref(tty); ToRecv = sGetRxCnt(cp); - if (ld) - space = ld->receive_room(tty); + space = tty->receive_room; if (space > 2 * TTY_FLIPBUF_SIZE) space = 2 * TTY_FLIPBUF_SIZE; - cbuf = tty->flip.char_buf; - fbuf = tty->flip.flag_buf; count = 0; #ifdef ROCKET_DEBUG_INTR printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space); @@ -350,9 +347,13 @@ static void rp_do_receive(struct r_port *info, if (ToRecv > space) ToRecv = space; + ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv); if (ToRecv <= 0) goto done; + cbuf = chead; + fbuf = fhead; + /* * if status indicates there are errored characters in the * FIFO, then enter status mode (a word in FIFO holds @@ -399,7 +400,7 @@ static void rp_do_receive(struct r_port *info, else if (CharNStat & STMRCVROVRH) *fbuf++ = TTY_OVERRUN; else - *fbuf++ = 0; + *fbuf++ = TTY_NORMAL; *cbuf++ = CharNStat & 0xff; count++; ToRecv--; @@ -426,13 +427,13 @@ static void rp_do_receive(struct r_port *info, sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); if (ToRecv & 1) cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); - memset(fbuf, 0, ToRecv); + memset(fbuf, TTY_NORMAL, ToRecv); cbuf += ToRecv; fbuf += ToRecv; count += ToRecv; } /* Push the data up to the tty layer */ - ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); + ld->receive_buf(tty, cbuf, fbuf, count); done: tty_ldisc_deref(ld); } diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 5b187c895c18..71093a9fc462 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -275,7 +275,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t int paste_selection(struct tty_struct *tty) { struct vc_data *vc = (struct vc_data *)tty->driver_data; - int pasted = 0, count; + int pasted = 0; + unsigned int count; struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); @@ -293,7 +294,7 @@ int paste_selection(struct tty_struct *tty) continue; } count = sel_buffer_lth - pasted; - count = min(count, tty->ldisc.receive_room(tty)); + count = min(count, tty->receive_room); tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index dda30e42ec79..80a5b840e22f 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -194,11 +194,6 @@ static inline void a2232_receive_char(struct a2232_port *port, int ch, int err) */ struct tty_struct *tty = port->gs.tty; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - return; - - tty->flip.count++; - #if 0 switch(err) { case TTY_BREAK: @@ -212,8 +207,7 @@ static inline void a2232_receive_char(struct a2232_port *port, int ch, int err) } #endif - *tty->flip.flag_buf_ptr++ = err; - *tty->flip.char_buf_ptr++ = ch; + tty_insert_flip_char(tty, ch, err); tty_flip_buffer_push(tty); } diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index a580748b92a1..f36342ae8e7e 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -422,45 +422,35 @@ cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp) base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; return IRQ_HANDLED; } - if (tty->flip.count < TTY_FLIPBUF_SIZE){ - tty->flip.count++; + if (tty_buffer_request_room(tty, 1) != 0){ if (err & info->read_status_mask){ if(err & CyBREAK){ - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = data; + tty_insert_flip_char(tty, data, TTY_BREAK); if (info->flags & ASYNC_SAK){ do_SAK(tty); } }else if(err & CyFRAME){ - *tty->flip.flag_buf_ptr++ = TTY_FRAME; - *tty->flip.char_buf_ptr++ = data; + tty_insert_flip_char(tty, data, TTY_FRAME); }else if(err & CyPARITY){ - *tty->flip.flag_buf_ptr++ = TTY_PARITY; - *tty->flip.char_buf_ptr++ = data; + tty_insert_flip_char(tty, data, TTY_PARITY); }else if(err & CyOVERRUN){ - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); /* If the flip buffer itself is overflowing, we still loose the next incoming character. */ - if(tty->flip.count < TTY_FLIPBUF_SIZE){ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = data; - } + tty_insert_flip_char(tty, data, TTY_NORMAL); + } /* These two conditions may imply */ /* a normal read should be done. */ /* else if(data & CyTIMEOUT) */ /* else if(data & CySPECHAR) */ }else{ - *tty->flip.flag_buf_ptr++ = 0; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, 0, TTY_NORMAL); } }else{ - *tty->flip.flag_buf_ptr++ = 0; - *tty->flip.char_buf_ptr++ = 0; + tty_insert_flip_char(tty, data, TTY_NORMAL); } }else{ /* there was a software buffer overrun @@ -692,12 +682,7 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp) #endif while(char_count--){ data = base_addr[CyRDR]; - if (tty->flip.count >= TTY_FLIPBUF_SIZE){ - continue; - } - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = data; + tty_insert_flip_char(tty, data, TTY_NORMAL); #ifdef CYCLOM_16Y_HACK udelay(10L); #endif diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 0bbfce43031c..0a574bdbce36 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -85,6 +85,7 @@ #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/mm.h> #include <linux/serial.h> #include <linux/fcntl.h> @@ -665,7 +666,7 @@ static inline void sx_receive_exc(struct specialix_board * bp) struct specialix_port *port; struct tty_struct *tty; unsigned char status; - unsigned char ch; + unsigned char ch, flag; func_enter(); @@ -676,8 +677,6 @@ static inline void sx_receive_exc(struct specialix_board * bp) return; } tty = port->tty; - dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n", - port, tty->flip.count, TTY_FLIPBUF_SIZE); status = sx_in(bp, CD186x_RCSR); @@ -691,7 +690,7 @@ static inline void sx_receive_exc(struct specialix_board * bp) /* This flip buffer check needs to be below the reading of the status register to reset the chip's IRQ.... */ - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + if (tty_buffer_request_room(tty, 1) == 0) { dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n", board_No(bp), port_No(port)); func_exit(); @@ -712,26 +711,24 @@ static inline void sx_receive_exc(struct specialix_board * bp) } else if (status & RCSR_BREAK) { dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n", board_No(bp), port_No(port)); - *tty->flip.flag_buf_ptr++ = TTY_BREAK; + flag = TTY_BREAK; if (port->flags & ASYNC_SAK) do_SAK(tty); } else if (status & RCSR_PE) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; + flag = TTY_PARITY; else if (status & RCSR_FE) - *tty->flip.flag_buf_ptr++ = TTY_FRAME; + flag = TTY_FRAME; else if (status & RCSR_OE) - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + flag = TTY_OVERRUN; else - *tty->flip.flag_buf_ptr++ = 0; - - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - schedule_delayed_work(&tty->flip.work, 1); + flag = TTY_NORMAL; + if(tty_insert_flip_char(tty, ch, flag)) + tty_flip_buffer_push(tty); func_exit(); } @@ -755,18 +752,11 @@ static inline void sx_receive(struct specialix_board * bp) dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count); port->hits[count > 8 ? 9 : count]++; - while (count--) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { - printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n", - board_No(bp), port_No(port)); - break; - } - *tty->flip.char_buf_ptr++ = sx_in(bp, CD186x_RDR); - *tty->flip.flag_buf_ptr++ = 0; - tty->flip.count++; - } - schedule_delayed_work(&tty->flip.work, 1); + tty_buffer_request_room(tty, count); + while (count--) + tty_insert_flip_char(tty, sx_in(bp, CD186x_RDR), TTY_NORMAL); + tty_flip_buffer_push(tty); func_exit(); } diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index acef2abf3f0d..0e20780d4a29 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -2901,7 +2901,8 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) if (portp->tty != (struct tty_struct *) NULL) { if (portp->tty->driver_data == portp) { portp->stats.ttystate = portp->tty->flags; - portp->stats.rxbuffered = portp->tty->flip.count; + /* No longer available as a statistic */ + portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */ if (portp->tty->termios != (struct termios *) NULL) { portp->stats.cflags = portp->tty->termios->c_cflag; portp->stats.iflags = portp->tty->termios->c_iflag; @@ -4045,9 +4046,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); len = inb(ioaddr + EREG_DATA); - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) { len = MIN(len, sizeof(stl_unwanted)); outb((RDSR + portp->uartaddr), ioaddr); insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); @@ -4056,12 +4055,10 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) } else { len = MIN(len, buflen); if (len > 0) { + unsigned char *ptr; outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; + tty_prepare_flip_string(tty, &ptr, len); + insb((ioaddr + EREG_DATA), ptr, len); tty_schedule_flip(tty); portp->stats.rxtotal += len; } @@ -4085,8 +4082,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) portp->stats.txxoff++; goto stl_rxalldone; } - if ((tty != (struct tty_struct *) NULL) && - ((portp->rxignoremsk & status) == 0)) { + if (tty != NULL && (portp->rxignoremsk & status) == 0) { if (portp->rxmarkmsk & status) { if (status & ST_BREAK) { status = TTY_BREAK; @@ -4106,14 +4102,8 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) } else { status = 0; } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } + tty_insert_flip_char(tty, ch, status); + tty_schedule_flip(tty); } } else { printk("STALLION: bad RX interrupt ack value=%x\n", ioack); @@ -5012,9 +5002,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) len = inb(ioaddr + XP_DATA) + 1; if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) { len = MIN(len, sizeof(stl_unwanted)); outb(GRXFIFO, (ioaddr + XP_ADDR)); insb((ioaddr + XP_DATA), &stl_unwanted[0], len); @@ -5023,12 +5011,10 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) } else { len = MIN(len, buflen); if (len > 0) { + unsigned char *ptr; outb(GRXFIFO, (ioaddr + XP_ADDR)); - insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; + tty_prepare_flip_string(tty, &ptr, len); + insb((ioaddr + XP_DATA), ptr, len); tty_schedule_flip(tty); portp->stats.rxtotal += len; } @@ -5096,14 +5082,8 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch status = 0; } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } + tty_insert_flip_char(tty, ch, status); + tty_schedule_flip(tty); if (status == 0) portp->stats.rxtotal++; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 564f31778eb3..64bf89cb574f 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1085,6 +1085,7 @@ static inline void sx_receive_chars (struct sx_port *port) int rx_op; struct tty_struct *tty; int copied=0; + unsigned char *rp; func_enter2 (); tty = port->gs.tty; @@ -1095,8 +1096,8 @@ static inline void sx_receive_chars (struct sx_port *port) sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c); /* Don't copy more bytes than there is room for in the buffer */ - if (tty->flip.count + c > TTY_FLIPBUF_SIZE) - c = TTY_FLIPBUF_SIZE - tty->flip.count; + + c = tty_prepare_flip_string(tty, &rp, c); sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); @@ -1111,14 +1112,8 @@ static inline void sx_receive_chars (struct sx_port *port) sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c, read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op), CHAN_OFFSET(port, hi_rxbuf)); - memcpy_fromio (tty->flip.char_buf_ptr, + memcpy_fromio (rp, port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c); - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c); - - /* Update the kernel buffer end */ - tty->flip.count += c; - tty->flip.char_buf_ptr += c; - tty->flip.flag_buf_ptr += c; /* This one last. ( Not essential.) It allows the card to start putting more data into the buffer! diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 789572fc002b..9f1b466c4f84 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1467,6 +1467,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) { int Fifocount; u16 status; + int work = 0; unsigned char DataByte; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; @@ -1487,6 +1488,8 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) /* flush the receive FIFO */ while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) { + int flag; + /* read one byte from RxFIFO */ outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY), info->io_base + CCAR ); @@ -1498,13 +1501,9 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - continue; - - *tty->flip.char_buf_ptr = DataByte; icount->rx++; - *tty->flip.flag_buf_ptr = 0; + flag = 0; if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) { printk("rxerr=%04X\n",status); @@ -1530,41 +1529,31 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) status &= info->read_status_mask; if (status & RXSTATUS_BREAK_RECEIVED) { - *tty->flip.flag_buf_ptr = TTY_BREAK; + flag = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (status & RXSTATUS_PARITY_ERROR) - *tty->flip.flag_buf_ptr = TTY_PARITY; + flag = TTY_PARITY; else if (status & RXSTATUS_FRAMING_ERROR) - *tty->flip.flag_buf_ptr = TTY_FRAME; - if (status & RXSTATUS_OVERRUN) { - /* Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } - } + flag = TTY_FRAME; } /* end of if (error) */ - - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + tty_insert_flip_char(tty, DataByte, flag); + if (status & RXSTATUS_OVERRUN) { + /* Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + work += tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } } if ( debug_level >= DEBUG_LEVEL_ISR ) { - printk("%s(%d):mgsl_isr_receive_data flip count=%d\n", - __FILE__,__LINE__,tty->flip.count); printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", __FILE__,__LINE__,icount->rx,icount->brk, icount->parity,icount->frame,icount->overrun); } - if ( tty->flip.count ) + if(work) tty_flip_buffer_push(tty); } diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 41759cd70a4f..79c81def4104 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1749,6 +1749,9 @@ static void rx_async(struct slgt_info *info) unsigned char status; struct slgt_desc *bufs = info->rbufs; int i, count; + int chars = 0; + int stat; + unsigned char ch; start = end = info->rbuf_current; @@ -1760,16 +1763,15 @@ static void rx_async(struct slgt_info *info) DBGDATA(info, p, count, "rx"); for(i=0 ; i < count; i+=2, p+=2) { - if (tty) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - tty_flip_buffer_push(tty); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - *tty->flip.char_buf_ptr = *p; - *tty->flip.flag_buf_ptr = 0; + if (tty && chars) { + tty_flip_buffer_push(tty); + chars = 0; } + ch = *p; icount->rx++; + stat = 0; + if ((status = *(p+1) & (BIT9 + BIT8))) { if (status & BIT9) icount->parity++; @@ -1778,17 +1780,14 @@ static void rx_async(struct slgt_info *info) /* discard char if tty control flags say so */ if (status & info->ignore_status_mask) continue; - if (tty) { - if (status & BIT9) - *tty->flip.flag_buf_ptr = TTY_PARITY; - else if (status & BIT8) - *tty->flip.flag_buf_ptr = TTY_FRAME; - } + if (status & BIT9) + stat = TTY_PARITY; + else if (status & BIT8) + stat = TTY_FRAME; } if (tty) { - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + tty_insert_flip_char(tty, ch, stat); + chars++; } } @@ -1811,7 +1810,7 @@ static void rx_async(struct slgt_info *info) break; } - if (tty && tty->flip.count) + if (tty && chars) tty_flip_buffer_push(tty); } @@ -2029,7 +2028,7 @@ static void isr_serial(struct slgt_info *info) if (info->tty) { if (!(status & info->ignore_status_mask)) { if (info->read_status_mask & MASK_BREAK) { - *info->tty->flip.flag_buf_ptr = TTY_BREAK; + tty_insert_flip_char(info->tty, 0, TTY_BREAK); if (info->flags & ASYNC_SAK) do_SAK(info->tty); } diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index a9467e7d3747..960adb256fbb 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -2196,7 +2196,7 @@ void isr_rxint(SLMP_INFO * info) if ( tty ) { if (!(status & info->ignore_status_mask1)) { if (info->read_status_mask1 & BRKD) { - *tty->flip.flag_buf_ptr = TTY_BREAK; + tty_insert_flip_char(tty, 0, TTY_BREAK); if (info->flags & ASYNC_SAK) do_SAK(tty); } @@ -2240,16 +2240,10 @@ void isr_rxrdy(SLMP_INFO * info) while((status = read_reg(info,CST0)) & BIT0) { + int flag = 0; + int over = 0; DataByte = read_reg(info,TRB); - if ( tty ) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - continue; - - *tty->flip.char_buf_ptr = DataByte; - *tty->flip.flag_buf_ptr = 0; - } - icount->rx++; if ( status & (PE + FRME + OVRN) ) { @@ -2272,42 +2266,34 @@ void isr_rxrdy(SLMP_INFO * info) if ( tty ) { if (status & PE) - *tty->flip.flag_buf_ptr = TTY_PARITY; + flag = TTY_PARITY; else if (status & FRME) - *tty->flip.flag_buf_ptr = TTY_FRAME; + flag = TTY_FRAME; if (status & OVRN) { /* Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } + over = 1; } } } /* end of if (error) */ if ( tty ) { - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + tty_insert_flip_char(tty, DataByte, flag); + if (over) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); } } if ( debug_level >= DEBUG_LEVEL_ISR ) { - printk("%s(%d):%s isr_rxrdy() flip count=%d\n", - __FILE__,__LINE__,info->device_name, - tty ? tty->flip.count : 0); printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n", __FILE__,__LINE__,info->device_name, icount->rx,icount->brk,icount->parity, icount->frame,icount->overrun); } - if ( tty && tty->flip.count ) + if ( tty ) tty_flip_buffer_push(tty); } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4b1eef51ec59..1eda82b31a61 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -166,9 +166,12 @@ static struct tty_struct *alloc_tty_struct(void) return tty; } +static void tty_buffer_free_all(struct tty_struct *); + static inline void free_tty_struct(struct tty_struct *tty) { kfree(tty->write_buf); + tty_buffer_free_all(tty); kfree(tty); } @@ -231,6 +234,201 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) } /* + * Tty buffer allocation management + */ + +static void tty_buffer_free_all(struct tty_struct *tty) +{ + struct tty_buffer *thead; + while((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + kfree(thead); + } + while((thead = tty->buf.free) != NULL) { + tty->buf.free = thead->next; + kfree(thead); + } + tty->buf.tail = NULL; +} + +static void tty_buffer_init(struct tty_struct *tty) +{ + tty->buf.head = NULL; + tty->buf.tail = NULL; + tty->buf.free = NULL; +} + +static struct tty_buffer *tty_buffer_alloc(size_t size) +{ + struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); + if(p == NULL) + return NULL; + p->used = 0; + p->size = size; + p->next = NULL; + p->char_buf_ptr = (char *)(p->data); + p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; +/* printk("Flip create %p\n", p); */ + return p; +} + +/* Must be called with the tty_read lock held. This needs to acquire strategy + code to decide if we should kfree or relink a given expired buffer */ + +static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) +{ + /* Dumb strategy for now - should keep some stats */ +/* printk("Flip dispose %p\n", b); */ + if(b->size >= 512) + kfree(b); + else { + b->next = tty->buf.free; + tty->buf.free = b; + } +} + +static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) +{ + struct tty_buffer **tbh = &tty->buf.free; + while((*tbh) != NULL) { + struct tty_buffer *t = *tbh; + if(t->size >= size) { + *tbh = t->next; + t->next = NULL; + t->used = 0; + /* DEBUG ONLY */ + memset(t->data, '*', size); +/* printk("Flip recycle %p\n", t); */ + return t; + } + tbh = &((*tbh)->next); + } + /* Round the buffer size out */ + size = (size + 0xFF) & ~ 0xFF; + return tty_buffer_alloc(size); + /* Should possibly check if this fails for the largest buffer we + have queued and recycle that ? */ +} + +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + struct tty_buffer *b = tty->buf.head, *n; + int left = 0; + + /* OPTIMISATION: We could keep a per tty "zero" sized buffer to + remove this conditional if its worth it. This would be invisible + to the callers */ + if(b != NULL) + left = b->size - b->used; + if(left >= size) + return size; + /* This is the slow path - looking for new buffers to use */ + n = tty_buffer_find(tty, size); + if(n == NULL) + return left; + n->next = b; + if(b != NULL) + b->next = n; + else + tty->buf.head = n; + tty->buf.tail = n; + return size; +} + +EXPORT_SYMBOL_GPL(tty_buffer_request_room); + +int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if(unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + copied += space; + chars += space; +/* printk("Flip insert %d.\n", space); */ + } + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + while (unlikely(size > copied)); + return copied; +} + +EXPORT_SYMBOL_GPL(tty_insert_flip_string); + +int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if(unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memcpy(tb->flag_buf_ptr + tb->used, flags, space); + tb->used += space; + copied += space; + chars += space; + flags += space; + } + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + while (unlikely(size > copied)); + return copied; +} + +EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); + + +/* + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for normal characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + */ + +int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) +{ + int space = tty_buffer_request_room(tty, size); + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + return space; +} + +EXPORT_SYMBOL_GPL(tty_prepare_flip_string); + +/* + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + */ + +int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) +{ + int space = tty_buffer_request_room(tty, size); + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + *flags = tb->flag_buf_ptr + tb->used; + tb->used += space; + return space; +} + +EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); + + + +/* * This is probably overkill for real world processors but * they are not on hot paths so a little discipline won't do * any harm. @@ -492,6 +690,17 @@ restart: if (ld == NULL) return -EINVAL; + /* + * No more input please, we are switching. The new ldisc + * will update this value in the ldisc open function + */ + + tty->receive_room = 0; + + /* + * Problem: What do we do if this blocks ? + */ + tty_wait_until_sent(tty, 0); if (tty->ldisc.num == ldisc) { @@ -560,9 +769,9 @@ restart: * we say so later on. */ - work = cancel_delayed_work(&tty->flip.work); + work = cancel_delayed_work(&tty->buf.work); /* - * Wait for ->hangup_work and ->flip.work handlers to terminate + * Wait for ->hangup_work and ->buf.work handlers to terminate */ flush_scheduled_work(); @@ -616,7 +825,7 @@ restart: /* Restart it in case no characters kick it off. Safe if already running */ if (work) - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); return retval; } @@ -1721,10 +1930,10 @@ static void release_dev(struct file * filp) */ clear_bit(TTY_LDISC, &tty->flags); clear_bit(TTY_DONT_FLIP, &tty->flags); - cancel_delayed_work(&tty->flip.work); + cancel_delayed_work(&tty->buf.work); /* - * Wait for ->hangup_work and ->flip.work handlers to terminate + * Wait for ->hangup_work and ->buf.work handlers to terminate */ flush_scheduled_work(); @@ -2518,17 +2727,15 @@ EXPORT_SYMBOL(do_SAK); /* * This routine is called out of the software interrupt to flush data - * from the flip buffer to the line discipline. + * from the buffer chain to the line discipline. */ static void flush_to_ldisc(void *private_) { struct tty_struct *tty = (struct tty_struct *) private_; - unsigned char *cp; - char *fp; - int count; unsigned long flags; struct tty_ldisc *disc; + struct tty_buffer *tbuf; disc = tty_ldisc_ref(tty); if (disc == NULL) /* !TTY_LDISC */ @@ -2538,28 +2745,22 @@ static void flush_to_ldisc(void *private_) /* * Do it after the next timer tick: */ - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); goto out; } spin_lock_irqsave(&tty->read_lock, flags); - if (tty->flip.buf_num) { - cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; - fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; - tty->flip.buf_num = 0; - tty->flip.char_buf_ptr = tty->flip.char_buf; - tty->flip.flag_buf_ptr = tty->flip.flag_buf; - } else { - cp = tty->flip.char_buf; - fp = tty->flip.flag_buf; - tty->flip.buf_num = 1; - tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; - tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; - } - count = tty->flip.count; - tty->flip.count = 0; + while((tbuf = tty->buf.head) != NULL) { + tty->buf.head = tbuf->next; + spin_unlock_irqrestore(&tty->read_lock, flags); + /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ + disc->receive_buf(tty, tbuf->char_buf_ptr, + tbuf->flag_buf_ptr, + tbuf->used); + spin_lock_irqsave(&tty->read_lock, flags); + tty_buffer_free(tty, tbuf); + } + tty->buf.tail = NULL; spin_unlock_irqrestore(&tty->read_lock, flags); - - disc->receive_buf(tty, cp, fp, count); out: tty_ldisc_deref(disc); } @@ -2654,11 +2855,12 @@ void tty_flip_buffer_push(struct tty_struct *tty) if (tty->low_latency) flush_to_ldisc((void *) tty); else - schedule_delayed_work(&tty->flip.work, 1); + schedule_delayed_work(&tty->buf.work, 1); } EXPORT_SYMBOL(tty_flip_buffer_push); + /* * This subroutine initializes a tty structure. */ @@ -2669,10 +2871,10 @@ static void initialize_tty_struct(struct tty_struct *tty) tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); tty->pgrp = -1; tty->overrun_time = jiffies; - tty->flip.char_buf_ptr = tty->flip.char_buf; - tty->flip.flag_buf_ptr = tty->flip.flag_buf; - INIT_WORK(&tty->flip.work, flush_to_ldisc, tty); - init_MUTEX(&tty->flip.pty_sem); + tty->buf.head = tty->buf.tail = NULL; + tty_buffer_init(tty); + INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); + init_MUTEX(&tty->buf.pty_sem); init_MUTEX(&tty->termios_sem); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index 4d75c261f98a..cb82ebf4cb07 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -993,11 +993,10 @@ static void vioHandleData(struct HvLpEvent *event) * Don't attempt to copy more data into the buffer than we * have room for because it would fail without indication. */ - if ((tty->flip.count + 1) > TTY_FLIPBUF_SIZE) { + if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) { printk(VIOCONS_KERN_WARN "input buffer overflow!\n"); break; } - tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL); } /* if cevent->len == 0 then no data was added to the buffer and flip.count == 0 */ diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 33e71e23b212..d9325281e482 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -434,13 +434,7 @@ static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp) SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); return IRQ_HANDLED; } - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.char_buf_ptr = ch; - *tty->flip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - } + tty_insert_flip_char(tty, ch, 0); /* Check if another character is already ready; in that case, the * spcond_int() function must be used, because this character may have an @@ -487,13 +481,7 @@ static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp) else err = 0; - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.char_buf_ptr = ch; - *tty->flip.flag_buf_ptr = err; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - } + tty_insert_flip_char(tty, ch, err); /* ++TeSche: *All* errors have to be cleared manually, * else the condition persists for the next chars |