diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/serial/cypress_m8.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 163386336a5d..08c65c1a3771 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
@@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) | |||
682 | { | 682 | { |
683 | struct cypress_private *priv = usb_get_serial_port_data(port); | 683 | struct cypress_private *priv = usb_get_serial_port_data(port); |
684 | unsigned int c_cflag; | 684 | unsigned int c_cflag; |
685 | unsigned long flags; | ||
686 | int bps; | 685 | int bps; |
687 | long timeout; | 686 | long timeout; |
688 | wait_queue_t wait; | 687 | wait_queue_t wait; |
@@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) | |||
690 | dbg("%s - port %d", __FUNCTION__, port->number); | 689 | dbg("%s - port %d", __FUNCTION__, port->number); |
691 | 690 | ||
692 | /* wait for data to drain from buffer */ | 691 | /* wait for data to drain from buffer */ |
693 | spin_lock_irqsave(&priv->lock, flags); | 692 | spin_lock_irq(&priv->lock); |
694 | timeout = CYPRESS_CLOSING_WAIT; | 693 | timeout = CYPRESS_CLOSING_WAIT; |
695 | init_waitqueue_entry(&wait, current); | 694 | init_waitqueue_entry(&wait, current); |
696 | add_wait_queue(&port->tty->write_wait, &wait); | 695 | add_wait_queue(&port->tty->write_wait, &wait); |
@@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) | |||
698 | set_current_state(TASK_INTERRUPTIBLE); | 697 | set_current_state(TASK_INTERRUPTIBLE); |
699 | if (cypress_buf_data_avail(priv->buf) == 0 | 698 | if (cypress_buf_data_avail(priv->buf) == 0 |
700 | || timeout == 0 || signal_pending(current) | 699 | || timeout == 0 || signal_pending(current) |
701 | || !usb_get_intfdata(port->serial->interface)) | 700 | /* without mutex, allowed due to harmless failure mode */ |
701 | || port->serial->disconnected) | ||
702 | break; | 702 | break; |
703 | spin_unlock_irqrestore(&priv->lock, flags); | 703 | spin_unlock_irq(&priv->lock); |
704 | timeout = schedule_timeout(timeout); | 704 | timeout = schedule_timeout(timeout); |
705 | spin_lock_irqsave(&priv->lock, flags); | 705 | spin_lock_irq(&priv->lock); |
706 | } | 706 | } |
707 | set_current_state(TASK_RUNNING); | 707 | set_current_state(TASK_RUNNING); |
708 | remove_wait_queue(&port->tty->write_wait, &wait); | 708 | remove_wait_queue(&port->tty->write_wait, &wait); |
709 | /* clear out any remaining data in the buffer */ | 709 | /* clear out any remaining data in the buffer */ |
710 | cypress_buf_clear(priv->buf); | 710 | cypress_buf_clear(priv->buf); |
711 | spin_unlock_irqrestore(&priv->lock, flags); | 711 | spin_unlock_irq(&priv->lock); |
712 | 712 | ||
713 | /* writing is potentially harmful, lock must be taken */ | ||
714 | mutex_lock(&port->serial->disc_mutex); | ||
715 | if (port->serial->disconnected) { | ||
716 | mutex_unlock(&port->serial->disc_mutex); | ||
717 | return; | ||
718 | } | ||
713 | /* wait for characters to drain from device */ | 719 | /* wait for characters to drain from device */ |
714 | bps = tty_get_baud_rate(port->tty); | 720 | bps = tty_get_baud_rate(port->tty); |
715 | if (bps > 1200) | 721 | if (bps > 1200) |
@@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) | |||
727 | if (c_cflag & HUPCL) { | 733 | if (c_cflag & HUPCL) { |
728 | /* drop dtr and rts */ | 734 | /* drop dtr and rts */ |
729 | priv = usb_get_serial_port_data(port); | 735 | priv = usb_get_serial_port_data(port); |
730 | spin_lock_irqsave(&priv->lock, flags); | 736 | spin_lock_irq(&priv->lock); |
731 | priv->line_control = 0; | 737 | priv->line_control = 0; |
732 | priv->cmd_ctrl = 1; | 738 | priv->cmd_ctrl = 1; |
733 | spin_unlock_irqrestore(&priv->lock, flags); | 739 | spin_unlock_irq(&priv->lock); |
734 | cypress_write(port, NULL, 0); | 740 | cypress_write(port, NULL, 0); |
735 | } | 741 | } |
736 | } | 742 | } |
@@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp) | |||
738 | if (stats) | 744 | if (stats) |
739 | dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", | 745 | dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", |
740 | priv->bytes_in, priv->bytes_out, priv->cmd_count); | 746 | priv->bytes_in, priv->bytes_out, priv->cmd_count); |
747 | mutex_unlock(&port->serial->disc_mutex); | ||
741 | } /* cypress_close */ | 748 | } /* cypress_close */ |
742 | 749 | ||
743 | 750 | ||