|
@@ -76,6 +76,7 @@ struct ftdi_private {
|
|
|
struct async_icount icount;
|
|
|
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
|
|
char prev_status; /* Used for TIOCMIWAIT */
|
|
|
+ bool dev_gone; /* Used to abort TIOCMIWAIT */
|
|
|
char transmit_empty; /* If transmitter is empty or not */
|
|
|
struct usb_serial_port *port;
|
|
|
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
|
|
@@ -1681,6 +1682,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
|
|
init_waitqueue_head(&priv->delta_msr_wait);
|
|
|
|
|
|
priv->flags = ASYNC_LOW_LATENCY;
|
|
|
+ priv->dev_gone = false;
|
|
|
|
|
|
if (quirk && quirk->port_probe)
|
|
|
quirk->port_probe(priv);
|
|
@@ -1839,6 +1841,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
|
|
|
|
|
|
dbg("%s", __func__);
|
|
|
|
|
|
+ priv->dev_gone = true;
|
|
|
+ wake_up_interruptible_all(&priv->delta_msr_wait);
|
|
|
+
|
|
|
remove_sysfs_attrs(port);
|
|
|
|
|
|
kref_put(&priv->kref, ftdi_sio_priv_release);
|
|
@@ -2397,15 +2402,12 @@ static int ftdi_ioctl(struct tty_struct *tty,
|
|
|
*/
|
|
|
case TIOCMIWAIT:
|
|
|
cprev = priv->icount;
|
|
|
- while (1) {
|
|
|
+ while (!priv->dev_gone) {
|
|
|
interruptible_sleep_on(&priv->delta_msr_wait);
|
|
|
/* see if a signal did it */
|
|
|
if (signal_pending(current))
|
|
|
return -ERESTARTSYS;
|
|
|
cnow = priv->icount;
|
|
|
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
|
|
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
|
|
- return -EIO; /* no change => error */
|
|
|
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
|
|
|
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
|
|
|
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
|
|
@@ -2414,7 +2416,7 @@ static int ftdi_ioctl(struct tty_struct *tty,
|
|
|
}
|
|
|
cprev = cnow;
|
|
|
}
|
|
|
- /* not reached */
|
|
|
+ return -EIO;
|
|
|
break;
|
|
|
case TIOCSERGETLSR:
|
|
|
return get_lsr_info(port, (struct serial_struct __user *)arg);
|