summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/usb/hso.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 8e90891f0e42..4398289d503d 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1011,7 +1011,7 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
struct hso_serial *serial = get_serial_by_tty(tty);
struct ktermios *termios;
- if ((!tty) || (!tty->termios) || (!serial)) {
+ if (!serial) {
printk(KERN_ERR "%s: no tty structures", __func__);
return;
}
@@ -1053,14 +1053,14 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
termios->c_cflag |= CS8; /* character size 8 bits */
/* baud rate 115200 */
- tty_encode_baud_rate(serial->tty, 115200, 115200);
+ tty_encode_baud_rate(tty, 115200, 115200);
/*
* Force low_latency on; otherwise the pushes are scheduled;
* this is bad as it opens up the possibility of dropping bytes
* on the floor. We don't want to drop bytes on the floor. :)
*/
- serial->tty->low_latency = 1;
+ tty->low_latency = 1;
return;
}
@@ -1224,6 +1224,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
/* sanity check */
if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {
+ WARN_ON(1);
tty->driver_data = NULL;
D1("Failed to open port");
return -ENODEV;
@@ -1238,8 +1239,10 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
kref_get(&serial->parent->ref);
/* setup */
+ spin_lock_irq(&serial->serial_lock);
tty->driver_data = serial;
- serial->tty = tty;
+ serial->tty = tty_kref_get(tty);
+ spin_unlock_irq(&serial->serial_lock);
/* check for port already opened, if not set the termios */
serial->open_count++;
@@ -1281,6 +1284,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
D1("Closing serial port");
+ /* Open failed, no close cleanup required */
+ if (serial == NULL)
+ return;
+
mutex_lock(&serial->parent->mutex);
usb_gone = serial->parent->usb_gone;
@@ -1293,10 +1300,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
kref_put(&serial->parent->ref, hso_serial_ref_free);
if (serial->open_count <= 0) {
serial->open_count = 0;
- if (serial->tty) {
+ spin_lock_irq(&serial->serial_lock);
+ if (serial->tty == tty) {
serial->tty->driver_data = NULL;
serial->tty = NULL;
+ tty_kref_put(tty);
}
+ spin_unlock_irq(&serial->serial_lock);
if (!usb_gone)
hso_stop_serial_device(serial->parent);
tasklet_kill(&serial->unthrottle_tasklet);
@@ -1649,6 +1659,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
{
struct hso_serial *serial = urb->context;
int status = urb->status;
+ struct tty_struct *tty;
/* sanity check */
if (!serial) {
@@ -1658,14 +1669,18 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
+ tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
log_usb_status(status, __func__);
+ tty_kref_put(tty);
return;
}
hso_put_activity(serial->parent);
- if (serial->tty)
- tty_wakeup(serial->tty);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
hso_kick_transmit(serial);
D1(" ");
@@ -1702,6 +1717,7 @@ static void ctrl_callback(struct urb *urb)
struct hso_serial *serial = urb->context;
struct usb_ctrlrequest *req;
int status = urb->status;
+ struct tty_struct *tty;
/* sanity check */
if (!serial)
@@ -1709,9 +1725,11 @@ static void ctrl_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
+ tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
log_usb_status(status, __func__);
+ tty_kref_put(tty);
return;
}
@@ -1730,25 +1748,31 @@ static void ctrl_callback(struct urb *urb)
spin_unlock(&serial->serial_lock);
} else {
hso_put_activity(serial->parent);
- if (serial->tty)
- tty_wakeup(serial->tty);
+ if (tty)
+ tty_wakeup(tty);
/* response to a write command */
hso_kick_transmit(serial);
}
+ tty_kref_put(tty);
}
/* handle RX data for serial port */
static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
{
- struct tty_struct *tty = serial->tty;
+ struct tty_struct *tty;
int write_length_remaining = 0;
int curr_write_len;
+
/* Sanity check */
if (urb == NULL || serial == NULL) {
D1("serial = NULL");
return -2;
}
+ spin_lock(&serial->serial_lock);
+ tty = tty_kref_get(serial->tty);
+ spin_unlock(&serial->serial_lock);
+
/* Push data to tty */
if (tty) {
write_length_remaining = urb->actual_length -
@@ -1770,6 +1794,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
}
+ tty_kref_put(tty);
return write_length_remaining;
}
@@ -2779,15 +2804,20 @@ static void hso_serial_ref_free(struct kref *ref)
static void hso_free_interface(struct usb_interface *interface)
{
struct hso_serial *hso_dev;
+ struct tty_struct *tty;
int i;
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i]
&& (serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]);
- if (hso_dev->tty)
- tty_hangup(hso_dev->tty);
+ spin_lock_irq(&hso_dev->serial_lock);
+ tty = tty_kref_get(hso_dev->tty);
+ spin_unlock_irq(&hso_dev->serial_lock);
+ if (tty)
+ tty_hangup(tty);
mutex_lock(&hso_dev->parent->mutex);
+ tty_kref_put(tty);
hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex);
kref_put(&serial_table[i]->ref, hso_serial_ref_free);