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: Gianluca Anzolin <gianluca@sottospazio.it>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
This commit is contained in:
Gianluca Anzolin 2013-07-29 17:08:10 +02:00 коммит произвёл Gustavo Padovan
Родитель ebe937f74b
Коммит 54b926a143
1 изменённых файлов: 72 добавлений и 42 удалений

Просмотреть файл

@ -633,49 +633,61 @@ static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
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);
struct rfcomm_dev *dev;
struct rfcomm_dlc *dlc;
unsigned long flags;
int err, id;
int err;
id = tty->index;
BT_DBG("tty %p id %d", tty, id);
/* 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);
dev = rfcomm_dev_get(tty->index);
if (!dev)
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;
/* Attach TTY and open DLC */
rfcomm_dlc_lock(dlc);
tty->driver_data = dev;
dev->port.tty = tty;
rfcomm_dlc_unlock(dlc);
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);
if (err < 0)
return err;
goto error_no_dlc;
/* Wait for DLC to connect */
add_wait_queue(&dev->wait, &wait);
@ -702,15 +714,45 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait);
if (err == 0)
device_move(dev->tty_dev, rfcomm_get_device(dev),
DPM_ORDER_DEV_AFTER_PARENT);
if (err < 0)
goto error_no_connection;
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_dlc_unthrottle(dev->dlc);
return err;
return 0;
}
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);
if (!--dev->port.count) {
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))
tty_port_put(&dev->port);
} else
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)
@ -1118,6 +1146,8 @@ static const struct tty_operations rfcomm_ops = {
.wait_until_sent = rfcomm_tty_wait_until_sent,
.tiocmget = rfcomm_tty_tiocmget,
.tiocmset = rfcomm_tty_tiocmset,
.install = rfcomm_tty_install,
.cleanup = rfcomm_tty_cleanup,
};
int __init rfcomm_init_ttys(void)