diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aab567644b99..0ab8474b00cb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -56,6 +56,7 @@ static __u16 vendor = FTDI_VID; | |||
56 | static __u16 product; | 56 | static __u16 product; |
57 | 57 | ||
58 | struct ftdi_private { | 58 | struct ftdi_private { |
59 | struct kref kref; | ||
59 | ftdi_chip_type_t chip_type; | 60 | ftdi_chip_type_t chip_type; |
60 | /* type of device, either SIO or FT8U232AM */ | 61 | /* type of device, either SIO or FT8U232AM */ |
61 | int baud_base; /* baud base clock for divisor setting */ | 62 | int baud_base; /* baud base clock for divisor setting */ |
@@ -1354,6 +1355,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1354 | return -ENOMEM; | 1355 | return -ENOMEM; |
1355 | } | 1356 | } |
1356 | 1357 | ||
1358 | kref_init(&priv->kref); | ||
1357 | spin_lock_init(&priv->rx_lock); | 1359 | spin_lock_init(&priv->rx_lock); |
1358 | spin_lock_init(&priv->tx_lock); | 1360 | spin_lock_init(&priv->tx_lock); |
1359 | init_waitqueue_head(&priv->delta_msr_wait); | 1361 | init_waitqueue_head(&priv->delta_msr_wait); |
@@ -1470,6 +1472,13 @@ static void ftdi_shutdown(struct usb_serial *serial) | |||
1470 | dbg("%s", __func__); | 1472 | dbg("%s", __func__); |
1471 | } | 1473 | } |
1472 | 1474 | ||
1475 | static void ftdi_sio_priv_release(struct kref *k) | ||
1476 | { | ||
1477 | struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); | ||
1478 | |||
1479 | kfree(priv); | ||
1480 | } | ||
1481 | |||
1473 | static int ftdi_sio_port_remove(struct usb_serial_port *port) | 1482 | static int ftdi_sio_port_remove(struct usb_serial_port *port) |
1474 | { | 1483 | { |
1475 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1484 | 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) | |||
1484 | 1493 | ||
1485 | if (priv) { | 1494 | if (priv) { |
1486 | usb_set_serial_port_data(port, NULL); | 1495 | usb_set_serial_port_data(port, NULL); |
1487 | kfree(priv); | 1496 | kref_put(&priv->kref, ftdi_sio_priv_release); |
1488 | } | 1497 | } |
1489 | 1498 | ||
1490 | return 0; | 1499 | return 0; |
@@ -1549,7 +1558,8 @@ static int ftdi_open(struct tty_struct *tty, | |||
1549 | dev_err(&port->dev, | 1558 | dev_err(&port->dev, |
1550 | "%s - failed submitting read urb, error %d\n", | 1559 | "%s - failed submitting read urb, error %d\n", |
1551 | __func__, result); | 1560 | __func__, result); |
1552 | 1561 | else | |
1562 | kref_get(&priv->kref); | ||
1553 | 1563 | ||
1554 | return result; | 1564 | return result; |
1555 | } /* ftdi_open */ | 1565 | } /* ftdi_open */ |
@@ -1591,11 +1601,11 @@ static void ftdi_close(struct tty_struct *tty, | |||
1591 | mutex_unlock(&port->serial->disc_mutex); | 1601 | mutex_unlock(&port->serial->disc_mutex); |
1592 | 1602 | ||
1593 | /* cancel any scheduled reading */ | 1603 | /* cancel any scheduled reading */ |
1594 | cancel_delayed_work(&priv->rx_work); | 1604 | cancel_delayed_work_sync(&priv->rx_work); |
1595 | flush_scheduled_work(); | ||
1596 | 1605 | ||
1597 | /* shutdown our bulk read */ | 1606 | /* shutdown our bulk read */ |
1598 | usb_kill_urb(port->read_urb); | 1607 | usb_kill_urb(port->read_urb); |
1608 | kref_put(&priv->kref, ftdi_sio_priv_release); | ||
1599 | } /* ftdi_close */ | 1609 | } /* ftdi_close */ |
1600 | 1610 | ||
1601 | 1611 | ||