diff options
Diffstat (limited to 'drivers/serial/icom.c')
-rw-r--r-- | drivers/serial/icom.c | 57 |
1 files changed, 24 insertions, 33 deletions
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index eb31125c6a3..144a7a352b2 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c | |||
@@ -729,19 +729,20 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) | |||
729 | unsigned short int status; | 729 | unsigned short int status; |
730 | struct uart_icount *icount; | 730 | struct uart_icount *icount; |
731 | unsigned long offset; | 731 | unsigned long offset; |
732 | unsigned char flag; | ||
732 | 733 | ||
733 | trace(icom_port, "RCV_COMPLETE", 0); | 734 | trace(icom_port, "RCV_COMPLETE", 0); |
734 | rcv_buff = icom_port->next_rcv; | 735 | rcv_buff = icom_port->next_rcv; |
735 | 736 | ||
736 | status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); | 737 | status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); |
737 | while (status & SA_FL_RCV_DONE) { | 738 | while (status & SA_FL_RCV_DONE) { |
739 | int first = -1; | ||
738 | 740 | ||
739 | trace(icom_port, "FID_STATUS", status); | 741 | trace(icom_port, "FID_STATUS", status); |
740 | count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); | 742 | count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); |
741 | 743 | ||
744 | count = tty_buffer_request_room(tty, count); | ||
742 | trace(icom_port, "RCV_COUNT", count); | 745 | trace(icom_port, "RCV_COUNT", count); |
743 | if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) | ||
744 | count = TTY_FLIPBUF_SIZE - tty->flip.count; | ||
745 | 746 | ||
746 | trace(icom_port, "REAL_COUNT", count); | 747 | trace(icom_port, "REAL_COUNT", count); |
747 | 748 | ||
@@ -749,15 +750,10 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) | |||
749 | cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - | 750 | cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - |
750 | icom_port->recv_buf_pci; | 751 | icom_port->recv_buf_pci; |
751 | 752 | ||
752 | memcpy(tty->flip.char_buf_ptr,(unsigned char *) | 753 | /* Block copy all but the last byte as this may have status */ |
753 | ((unsigned long)icom_port->recv_buf + offset), count); | ||
754 | |||
755 | if (count > 0) { | 754 | if (count > 0) { |
756 | tty->flip.count += count - 1; | 755 | first = icom_port->recv_buf[offset]; |
757 | tty->flip.char_buf_ptr += count - 1; | 756 | tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1); |
758 | |||
759 | memset(tty->flip.flag_buf_ptr, 0, count); | ||
760 | tty->flip.flag_buf_ptr += count - 1; | ||
761 | } | 757 | } |
762 | 758 | ||
763 | icount = &icom_port->uart_port.icount; | 759 | icount = &icom_port->uart_port.icount; |
@@ -765,12 +761,14 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) | |||
765 | 761 | ||
766 | /* Break detect logic */ | 762 | /* Break detect logic */ |
767 | if ((status & SA_FLAGS_FRAME_ERROR) | 763 | if ((status & SA_FLAGS_FRAME_ERROR) |
768 | && (tty->flip.char_buf_ptr[0] == 0x00)) { | 764 | && first == 0) { |
769 | status &= ~SA_FLAGS_FRAME_ERROR; | 765 | status &= ~SA_FLAGS_FRAME_ERROR; |
770 | status |= SA_FLAGS_BREAK_DET; | 766 | status |= SA_FLAGS_BREAK_DET; |
771 | trace(icom_port, "BREAK_DET", 0); | 767 | trace(icom_port, "BREAK_DET", 0); |
772 | } | 768 | } |
773 | 769 | ||
770 | flag = TTY_NORMAL; | ||
771 | |||
774 | if (status & | 772 | if (status & |
775 | (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | | 773 | (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | |
776 | SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { | 774 | SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { |
@@ -797,33 +795,26 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) | |||
797 | status &= icom_port->read_status_mask; | 795 | status &= icom_port->read_status_mask; |
798 | 796 | ||
799 | if (status & SA_FLAGS_BREAK_DET) { | 797 | if (status & SA_FLAGS_BREAK_DET) { |
800 | *tty->flip.flag_buf_ptr = TTY_BREAK; | 798 | flag = TTY_BREAK; |
801 | } else if (status & SA_FLAGS_PARITY_ERROR) { | 799 | } else if (status & SA_FLAGS_PARITY_ERROR) { |
802 | trace(icom_port, "PARITY_ERROR", 0); | 800 | trace(icom_port, "PARITY_ERROR", 0); |
803 | *tty->flip.flag_buf_ptr = TTY_PARITY; | 801 | flag = TTY_PARITY; |
804 | } else if (status & SA_FLAGS_FRAME_ERROR) | 802 | } else if (status & SA_FLAGS_FRAME_ERROR) |
805 | *tty->flip.flag_buf_ptr = TTY_FRAME; | 803 | flag = TTY_FRAME; |
806 | 804 | ||
807 | if (status & SA_FLAGS_OVERRUN) { | ||
808 | /* | ||
809 | * Overrun is special, since it's | ||
810 | * reported immediately, and doesn't | ||
811 | * affect the current character | ||
812 | */ | ||
813 | if (tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
814 | tty->flip.count++; | ||
815 | tty->flip.flag_buf_ptr++; | ||
816 | tty->flip.char_buf_ptr++; | ||
817 | *tty->flip.flag_buf_ptr = TTY_OVERRUN; | ||
818 | } | ||
819 | } | ||
820 | } | 805 | } |
821 | 806 | ||
822 | tty->flip.flag_buf_ptr++; | 807 | tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag); |
823 | tty->flip.char_buf_ptr++; | 808 | |
824 | tty->flip.count++; | 809 | if (status & SA_FLAGS_OVERRUN) |
825 | ignore_char: | 810 | /* |
826 | icom_port->statStg->rcv[rcv_buff].flags = 0; | 811 | * Overrun is special, since it's |
812 | * reported immediately, and doesn't | ||
813 | * affect the current character | ||
814 | */ | ||
815 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
816 | ignore_char: | ||
817 | icom_port->statStg->rcv[rcv_buff].flags = 0; | ||
827 | icom_port->statStg->rcv[rcv_buff].leLength = 0; | 818 | icom_port->statStg->rcv[rcv_buff].leLength = 0; |
828 | icom_port->statStg->rcv[rcv_buff].WorkingLength = | 819 | icom_port->statStg->rcv[rcv_buff].WorkingLength = |
829 | (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); | 820 | (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); |