aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/serial/cypress_m8.c25
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