Commit 54b926a1 authored by Gianluca Anzolin's avatar Gianluca Anzolin Committed by Gustavo Padovan

Bluetooth: Move the tty initialization and cleanup out of open/close

Move the tty_struct initialization from rfcomm_tty_open() to
rfcomm_tty_install() and do the same for the cleanup moving the code from
rfcomm_tty_close() to rfcomm_tty_cleanup().

Add also extra error handling in rfcomm_tty_install() because, unlike
.open()/.close(), .cleanup() is not called if .install() fails.
Signed-off-by: default avatarGianluca Anzolin <gianluca@sottospazio.it>
Reviewed-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
parent ebe937f7
...@@ -633,49 +633,61 @@ static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev) ...@@ -633,49 +633,61 @@ static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
tty_flip_buffer_push(&dev->port); tty_flip_buffer_push(&dev->port);
} }
static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) /* do the reverse of install, clearing the tty fields and releasing the
* reference to tty_port
*/
static void rfcomm_tty_cleanup(struct tty_struct *tty)
{
struct rfcomm_dev *dev = tty->driver_data;
if (dev->tty_dev->parent)
device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
/* Close DLC and dettach TTY */
rfcomm_dlc_close(dev->dlc, 0);
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
rfcomm_dlc_lock(dev->dlc);
tty->driver_data = NULL;
dev->port.tty = NULL;
rfcomm_dlc_unlock(dev->dlc);
tty_port_put(&dev->port);
}
/* we acquire the tty_port reference since it's here the tty is first used
* by setting the termios. We also populate the driver_data field and install
* the tty port
*/
static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
struct rfcomm_dev *dev; struct rfcomm_dev *dev;
struct rfcomm_dlc *dlc; struct rfcomm_dlc *dlc;
unsigned long flags; int err;
int err, id;
id = tty->index;
BT_DBG("tty %p id %d", tty, id); dev = rfcomm_dev_get(tty->index);
/* We don't leak this refcount. For reasons which are not entirely
clear, the TTY layer will call our ->close() method even if the
open fails. We decrease the refcount there, and decreasing it
here too would cause breakage. */
dev = rfcomm_dev_get(id);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst,
dev->channel, dev->port.count);
spin_lock_irqsave(&dev->port.lock, flags);
if (++dev->port.count > 1) {
spin_unlock_irqrestore(&dev->port.lock, flags);
return 0;
}
spin_unlock_irqrestore(&dev->port.lock, flags);
dlc = dev->dlc; dlc = dev->dlc;
/* Attach TTY and open DLC */ /* Attach TTY and open DLC */
rfcomm_dlc_lock(dlc); rfcomm_dlc_lock(dlc);
tty->driver_data = dev; tty->driver_data = dev;
dev->port.tty = tty; dev->port.tty = tty;
rfcomm_dlc_unlock(dlc); rfcomm_dlc_unlock(dlc);
set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
/* install the tty_port */
err = tty_port_install(&dev->port, driver, tty);
if (err < 0)
goto error_no_dlc;
err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
if (err < 0) if (err < 0)
return err; goto error_no_dlc;
/* Wait for DLC to connect */ /* Wait for DLC to connect */
add_wait_queue(&dev->wait, &wait); add_wait_queue(&dev->wait, &wait);
...@@ -702,15 +714,45 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -702,15 +714,45 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait); remove_wait_queue(&dev->wait, &wait);
if (err == 0) if (err < 0)
device_move(dev->tty_dev, rfcomm_get_device(dev), goto error_no_connection;
DPM_ORDER_DEV_AFTER_PARENT);
device_move(dev->tty_dev, rfcomm_get_device(dev),
DPM_ORDER_DEV_AFTER_PARENT);
return 0;
error_no_connection:
rfcomm_dlc_close(dlc, err);
error_no_dlc:
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
tty_port_put(&dev->port);
return err;
}
static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
{
struct rfcomm_dev *dev = tty->driver_data;
unsigned long flags;
BT_DBG("tty %p id %d", tty, tty->index);
BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst,
dev->channel, dev->port.count);
spin_lock_irqsave(&dev->port.lock, flags);
dev->port.count++;
spin_unlock_irqrestore(&dev->port.lock, flags);
/*
* FIXME: rfcomm should use proper flow control for
* received data. This hack will be unnecessary and can
* be removed when that's implemented
*/
rfcomm_tty_copy_pending(dev); rfcomm_tty_copy_pending(dev);
rfcomm_dlc_unthrottle(dev->dlc); rfcomm_dlc_unthrottle(dev->dlc);
return err; return 0;
} }
static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
...@@ -727,25 +769,11 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -727,25 +769,11 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&dev->port.lock, flags); spin_lock_irqsave(&dev->port.lock, flags);
if (!--dev->port.count) { if (!--dev->port.count) {
spin_unlock_irqrestore(&dev->port.lock, flags); spin_unlock_irqrestore(&dev->port.lock, flags);
if (dev->tty_dev->parent)
device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
/* Close DLC and dettach TTY */
rfcomm_dlc_close(dev->dlc, 0);
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
rfcomm_dlc_lock(dev->dlc);
tty->driver_data = NULL;
dev->port.tty = NULL;
rfcomm_dlc_unlock(dev->dlc);
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
tty_port_put(&dev->port); tty_port_put(&dev->port);
} else } else
spin_unlock_irqrestore(&dev->port.lock, flags); spin_unlock_irqrestore(&dev->port.lock, flags);
tty_port_put(&dev->port);
} }
static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
...@@ -1118,6 +1146,8 @@ static const struct tty_operations rfcomm_ops = { ...@@ -1118,6 +1146,8 @@ static const struct tty_operations rfcomm_ops = {
.wait_until_sent = rfcomm_tty_wait_until_sent, .wait_until_sent = rfcomm_tty_wait_until_sent,
.tiocmget = rfcomm_tty_tiocmget, .tiocmget = rfcomm_tty_tiocmget,
.tiocmset = rfcomm_tty_tiocmset, .tiocmset = rfcomm_tty_tiocmset,
.install = rfcomm_tty_install,
.cleanup = rfcomm_tty_cleanup,
}; };
int __init rfcomm_init_ttys(void) int __init rfcomm_init_ttys(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment