diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c02e4602d90a..02e7f2d32d52 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -76,6 +76,7 @@ struct ftdi_private { | |||
76 | struct async_icount icount; | 76 | struct async_icount icount; |
77 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ | 77 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
78 | char prev_status; /* Used for TIOCMIWAIT */ | 78 | char prev_status; /* Used for TIOCMIWAIT */ |
79 | bool dev_gone; /* Used to abort TIOCMIWAIT */ | ||
79 | char transmit_empty; /* If transmitter is empty or not */ | 80 | char transmit_empty; /* If transmitter is empty or not */ |
80 | struct usb_serial_port *port; | 81 | struct usb_serial_port *port; |
81 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface | 82 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface |
@@ -1681,6 +1682,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1681 | init_waitqueue_head(&priv->delta_msr_wait); | 1682 | init_waitqueue_head(&priv->delta_msr_wait); |
1682 | 1683 | ||
1683 | priv->flags = ASYNC_LOW_LATENCY; | 1684 | priv->flags = ASYNC_LOW_LATENCY; |
1685 | priv->dev_gone = false; | ||
1684 | 1686 | ||
1685 | if (quirk && quirk->port_probe) | 1687 | if (quirk && quirk->port_probe) |
1686 | quirk->port_probe(priv); | 1688 | quirk->port_probe(priv); |
@@ -1839,6 +1841,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) | |||
1839 | 1841 | ||
1840 | dbg("%s", __func__); | 1842 | dbg("%s", __func__); |
1841 | 1843 | ||
1844 | priv->dev_gone = true; | ||
1845 | wake_up_interruptible_all(&priv->delta_msr_wait); | ||
1846 | |||
1842 | remove_sysfs_attrs(port); | 1847 | remove_sysfs_attrs(port); |
1843 | 1848 | ||
1844 | kref_put(&priv->kref, ftdi_sio_priv_release); | 1849 | kref_put(&priv->kref, ftdi_sio_priv_release); |
@@ -2397,15 +2402,12 @@ static int ftdi_ioctl(struct tty_struct *tty, | |||
2397 | */ | 2402 | */ |
2398 | case TIOCMIWAIT: | 2403 | case TIOCMIWAIT: |
2399 | cprev = priv->icount; | 2404 | cprev = priv->icount; |
2400 | while (1) { | 2405 | while (!priv->dev_gone) { |
2401 | interruptible_sleep_on(&priv->delta_msr_wait); | 2406 | interruptible_sleep_on(&priv->delta_msr_wait); |
2402 | /* see if a signal did it */ | 2407 | /* see if a signal did it */ |
2403 | if (signal_pending(current)) | 2408 | if (signal_pending(current)) |
2404 | return -ERESTARTSYS; | 2409 | return -ERESTARTSYS; |
2405 | cnow = priv->icount; | 2410 | cnow = priv->icount; |
2406 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
2407 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) | ||
2408 | return -EIO; /* no change => error */ | ||
2409 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || | 2411 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || |
2410 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | 2412 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || |
2411 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || | 2413 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || |
@@ -2414,7 +2416,7 @@ static int ftdi_ioctl(struct tty_struct *tty, | |||
2414 | } | 2416 | } |
2415 | cprev = cnow; | 2417 | cprev = cnow; |
2416 | } | 2418 | } |
2417 | /* not reached */ | 2419 | return -EIO; |
2418 | break; | 2420 | break; |
2419 | case TIOCSERGETLSR: | 2421 | case TIOCSERGETLSR: |
2420 | return get_lsr_info(port, (struct serial_struct __user *)arg); | 2422 | return get_lsr_info(port, (struct serial_struct __user *)arg); |