synclink_gt fix missed serial input signal changes
authorPaul Fulghum <paulkf@microgate.com>
Wed, 6 Feb 2008 09:37:18 +0000 (01:37 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 6 Feb 2008 18:41:06 +0000 (10:41 -0800)
Fix missed serial input signal changes caused by rereading the serial
status register during interrupt processing.  Now processing is performed
on original status register value.

Signed-off-by: Paul Fulghum <paulkf@microgate.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/char/synclink_gt.c

index 5f6a5da696c755eb49e0232b7140424a268948ca..1f954acf2bac49125be4b18f0167eb437ec0cbe0 100644 (file)
@@ -2039,37 +2039,41 @@ static void bh_transmit(struct slgt_info *info)
                tty_wakeup(tty);
 }
 
-static void dsr_change(struct slgt_info *info)
+static void dsr_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT3) {
+               info->signals |= SerialSignal_DSR;
+               info->input_signal_events.dsr_up++;
+       } else {
+               info->signals &= ~SerialSignal_DSR;
+               info->input_signal_events.dsr_down++;
+       }
        DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DSR);
                return;
        }
        info->icount.dsr++;
-       if (info->signals & SerialSignal_DSR)
-               info->input_signal_events.dsr_up++;
-       else
-               info->input_signal_events.dsr_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
 }
 
-static void cts_change(struct slgt_info *info)
+static void cts_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT2) {
+               info->signals |= SerialSignal_CTS;
+               info->input_signal_events.cts_up++;
+       } else {
+               info->signals &= ~SerialSignal_CTS;
+               info->input_signal_events.cts_down++;
+       }
        DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_CTS);
                return;
        }
        info->icount.cts++;
-       if (info->signals & SerialSignal_CTS)
-               info->input_signal_events.cts_up++;
-       else
-               info->input_signal_events.cts_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2090,20 +2094,21 @@ static void cts_change(struct slgt_info *info)
        }
 }
 
-static void dcd_change(struct slgt_info *info)
+static void dcd_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT1) {
+               info->signals |= SerialSignal_DCD;
+               info->input_signal_events.dcd_up++;
+       } else {
+               info->signals &= ~SerialSignal_DCD;
+               info->input_signal_events.dcd_down++;
+       }
        DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DCD);
                return;
        }
        info->icount.dcd++;
-       if (info->signals & SerialSignal_DCD) {
-               info->input_signal_events.dcd_up++;
-       } else {
-               info->input_signal_events.dcd_down++;
-       }
 #if SYNCLINK_GENERIC_HDLC
        if (info->netcount) {
                if (info->signals & SerialSignal_DCD)
@@ -2126,20 +2131,21 @@ static void dcd_change(struct slgt_info *info)
        }
 }
 
-static void ri_change(struct slgt_info *info)
+static void ri_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT0) {
+               info->signals |= SerialSignal_RI;
+               info->input_signal_events.ri_up++;
+       } else {
+               info->signals &= ~SerialSignal_RI;
+               info->input_signal_events.ri_down++;
+       }
        DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_RI);
                return;
        }
-       info->icount.dcd++;
-       if (info->signals & SerialSignal_RI) {
-               info->input_signal_events.ri_up++;
-       } else {
-               info->input_signal_events.ri_down++;
-       }
+       info->icount.rng++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2190,13 +2196,13 @@ static void isr_serial(struct slgt_info *info)
        }
 
        if (status & IRQ_DSR)
-               dsr_change(info);
+               dsr_change(info, status);
        if (status & IRQ_CTS)
-               cts_change(info);
+               cts_change(info, status);
        if (status & IRQ_DCD)
-               dcd_change(info);
+               dcd_change(info, status);
        if (status & IRQ_RI)
-               ri_change(info);
+               ri_change(info, status);
 }
 
 static void isr_rdma(struct slgt_info *info)