|
@@ -56,6 +56,7 @@ static __u16 vendor = FTDI_VID;
|
|
|
static __u16 product;
|
|
|
|
|
|
struct ftdi_private {
|
|
|
+ struct kref kref;
|
|
|
ftdi_chip_type_t chip_type;
|
|
|
/* type of device, either SIO or FT8U232AM */
|
|
|
int baud_base; /* baud base clock for divisor setting */
|
|
@@ -1354,6 +1355,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
+ kref_init(&priv->kref);
|
|
|
spin_lock_init(&priv->rx_lock);
|
|
|
spin_lock_init(&priv->tx_lock);
|
|
|
init_waitqueue_head(&priv->delta_msr_wait);
|
|
@@ -1470,6 +1472,13 @@ static void ftdi_shutdown(struct usb_serial *serial)
|
|
|
dbg("%s", __func__);
|
|
|
}
|
|
|
|
|
|
+static void ftdi_sio_priv_release(struct kref *k)
|
|
|
+{
|
|
|
+ struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
|
|
|
+
|
|
|
+ kfree(priv);
|
|
|
+}
|
|
|
+
|
|
|
static int ftdi_sio_port_remove(struct usb_serial_port *port)
|
|
|
{
|
|
|
struct ftdi_private *priv = usb_get_serial_port_data(port);
|
|
@@ -1484,7 +1493,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
|
|
|
|
|
|
if (priv) {
|
|
|
usb_set_serial_port_data(port, NULL);
|
|
|
- kfree(priv);
|
|
|
+ kref_put(&priv->kref, ftdi_sio_priv_release);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -1549,7 +1558,8 @@ static int ftdi_open(struct tty_struct *tty,
|
|
|
dev_err(&port->dev,
|
|
|
"%s - failed submitting read urb, error %d\n",
|
|
|
__func__, result);
|
|
|
-
|
|
|
+ else
|
|
|
+ kref_get(&priv->kref);
|
|
|
|
|
|
return result;
|
|
|
} /* ftdi_open */
|
|
@@ -1591,11 +1601,11 @@ static void ftdi_close(struct tty_struct *tty,
|
|
|
mutex_unlock(&port->serial->disc_mutex);
|
|
|
|
|
|
/* cancel any scheduled reading */
|
|
|
- cancel_delayed_work(&priv->rx_work);
|
|
|
- flush_scheduled_work();
|
|
|
+ cancel_delayed_work_sync(&priv->rx_work);
|
|
|
|
|
|
/* shutdown our bulk read */
|
|
|
usb_kill_urb(port->read_urb);
|
|
|
+ kref_put(&priv->kref, ftdi_sio_priv_release);
|
|
|
} /* ftdi_close */
|
|
|
|
|
|
|