diff options
Diffstat (limited to 'net/bluetooth/rfcomm/tty.c')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d3340dd52bcf..d030c69cb5a3 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -39,11 +39,6 @@ | |||
39 | #include <net/bluetooth/hci_core.h> | 39 | #include <net/bluetooth/hci_core.h> |
40 | #include <net/bluetooth/rfcomm.h> | 40 | #include <net/bluetooth/rfcomm.h> |
41 | 41 | ||
42 | #ifndef CONFIG_BT_RFCOMM_DEBUG | ||
43 | #undef BT_DBG | ||
44 | #define BT_DBG(D...) | ||
45 | #endif | ||
46 | |||
47 | #define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ | 42 | #define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ |
48 | #define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ | 43 | #define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ |
49 | #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ | 44 | #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ |
@@ -58,7 +53,7 @@ struct rfcomm_dev { | |||
58 | char name[12]; | 53 | char name[12]; |
59 | int id; | 54 | int id; |
60 | unsigned long flags; | 55 | unsigned long flags; |
61 | int opened; | 56 | atomic_t opened; |
62 | int err; | 57 | int err; |
63 | 58 | ||
64 | bdaddr_t src; | 59 | bdaddr_t src; |
@@ -261,6 +256,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
261 | dev->flags = req->flags & | 256 | dev->flags = req->flags & |
262 | ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); | 257 | ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); |
263 | 258 | ||
259 | atomic_set(&dev->opened, 0); | ||
260 | |||
264 | init_waitqueue_head(&dev->wait); | 261 | init_waitqueue_head(&dev->wait); |
265 | tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); | 262 | tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); |
266 | 263 | ||
@@ -301,18 +298,15 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) | |||
301 | out: | 298 | out: |
302 | write_unlock_bh(&rfcomm_dev_lock); | 299 | write_unlock_bh(&rfcomm_dev_lock); |
303 | 300 | ||
304 | if (err < 0) { | 301 | if (err < 0) |
305 | kfree(dev); | 302 | goto free; |
306 | return err; | ||
307 | } | ||
308 | 303 | ||
309 | dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); | 304 | dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); |
310 | 305 | ||
311 | if (IS_ERR(dev->tty_dev)) { | 306 | if (IS_ERR(dev->tty_dev)) { |
312 | err = PTR_ERR(dev->tty_dev); | 307 | err = PTR_ERR(dev->tty_dev); |
313 | list_del(&dev->list); | 308 | list_del(&dev->list); |
314 | kfree(dev); | 309 | goto free; |
315 | return err; | ||
316 | } | 310 | } |
317 | 311 | ||
318 | dev_set_drvdata(dev->tty_dev, dev); | 312 | dev_set_drvdata(dev->tty_dev, dev); |
@@ -324,16 +318,20 @@ out: | |||
324 | BT_ERR("Failed to create channel attribute"); | 318 | BT_ERR("Failed to create channel attribute"); |
325 | 319 | ||
326 | return dev->id; | 320 | return dev->id; |
321 | |||
322 | free: | ||
323 | kfree(dev); | ||
324 | return err; | ||
327 | } | 325 | } |
328 | 326 | ||
329 | static void rfcomm_dev_del(struct rfcomm_dev *dev) | 327 | static void rfcomm_dev_del(struct rfcomm_dev *dev) |
330 | { | 328 | { |
331 | BT_DBG("dev %p", dev); | 329 | BT_DBG("dev %p", dev); |
332 | 330 | ||
333 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | 331 | BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)); |
334 | BUG_ON(1); | 332 | |
335 | else | 333 | if (atomic_read(&dev->opened) > 0) |
336 | set_bit(RFCOMM_TTY_RELEASED, &dev->flags); | 334 | return; |
337 | 335 | ||
338 | write_lock_bh(&rfcomm_dev_lock); | 336 | write_lock_bh(&rfcomm_dev_lock); |
339 | list_del_init(&dev->list); | 337 | list_del_init(&dev->list); |
@@ -689,9 +687,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | |||
689 | if (!dev) | 687 | if (!dev) |
690 | return -ENODEV; | 688 | return -ENODEV; |
691 | 689 | ||
692 | BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened); | 690 | BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), |
691 | dev->channel, atomic_read(&dev->opened)); | ||
693 | 692 | ||
694 | if (dev->opened++ != 0) | 693 | if (atomic_inc_return(&dev->opened) > 1) |
695 | return 0; | 694 | return 0; |
696 | 695 | ||
697 | dlc = dev->dlc; | 696 | dlc = dev->dlc; |
@@ -747,9 +746,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) | |||
747 | if (!dev) | 746 | if (!dev) |
748 | return; | 747 | return; |
749 | 748 | ||
750 | BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); | 749 | BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, |
750 | atomic_read(&dev->opened)); | ||
751 | 751 | ||
752 | if (--dev->opened == 0) { | 752 | if (atomic_dec_and_test(&dev->opened)) { |
753 | if (dev->tty_dev->parent) | 753 | if (dev->tty_dev->parent) |
754 | device_move(dev->tty_dev, NULL); | 754 | device_move(dev->tty_dev, NULL); |
755 | 755 | ||
@@ -763,6 +763,14 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) | |||
763 | tty->driver_data = NULL; | 763 | tty->driver_data = NULL; |
764 | dev->tty = NULL; | 764 | dev->tty = NULL; |
765 | rfcomm_dlc_unlock(dev->dlc); | 765 | rfcomm_dlc_unlock(dev->dlc); |
766 | |||
767 | if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) { | ||
768 | write_lock_bh(&rfcomm_dev_lock); | ||
769 | list_del_init(&dev->list); | ||
770 | write_unlock_bh(&rfcomm_dev_lock); | ||
771 | |||
772 | rfcomm_dev_put(dev); | ||
773 | } | ||
766 | } | 774 | } |
767 | 775 | ||
768 | rfcomm_dev_put(dev); | 776 | rfcomm_dev_put(dev); |