Merge branch 'for-2.6.25' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerp...
[sfrench/cifs-2.6.git] / net / bluetooth / rfcomm / tty.c
index 22a832098d44057e120ae76cecda07ae2d48ca00..e4c779bb8d76e6cf9dfab3b82a3ae33f7276dc68 100644 (file)
@@ -95,9 +95,10 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
 
        BT_DBG("dev %p dlc %p", dev, dlc);
 
-       write_lock_bh(&rfcomm_dev_lock);
-       list_del_init(&dev->list);
-       write_unlock_bh(&rfcomm_dev_lock);
+       /* Refcount should only hit zero when called from rfcomm_dev_del()
+          which will have taken us off the list. Everything else are
+          refcounting bugs. */
+       BUG_ON(!list_empty(&dev->list));
 
        rfcomm_dlc_lock(dlc);
        /* Detach DLC if it's owned by this dev */
@@ -109,11 +110,6 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
 
        tty_unregister_device(rfcomm_tty_driver, dev->id);
 
-       /* Refcount should only hit zero when called from rfcomm_dev_del()
-          which will have taken us off the list. Everything else are
-          refcounting bugs. */
-       BUG_ON(!list_empty(&dev->list));
-
        kfree(dev);
 
        /* It's safe to call module_put() here because socket still
@@ -189,6 +185,23 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
        return conn ? &conn->dev : NULL;
 }
 
+static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+       struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+       bdaddr_t bdaddr;
+       baswap(&bdaddr, &dev->dst);
+       return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+       struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+       return sprintf(buf, "%d\n", dev->channel);
+}
+
+static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
+
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
        struct rfcomm_dev *dev;
@@ -281,6 +294,14 @@ out:
                return err;
        }
 
+       dev_set_drvdata(dev->tty_dev, dev);
+
+       if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
+               BT_ERR("Failed to create address attribute");
+
+       if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
+               BT_ERR("Failed to create channel attribute");
+
        return dev->id;
 }
 
@@ -288,7 +309,15 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
 {
        BT_DBG("dev %p", dev);
 
-       set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
+       if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+               BUG_ON(1);
+       else
+               set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
+
+       write_lock_bh(&rfcomm_dev_lock);
+       list_del_init(&dev->list);
+       write_unlock_bh(&rfcomm_dev_lock);
+
        rfcomm_dev_put(dev);
 }
 
@@ -400,7 +429,8 @@ static int rfcomm_release_dev(void __user *arg)
        if (dev->tty)
                tty_vhangup(dev->tty);
 
-       rfcomm_dev_del(dev);
+       if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+               rfcomm_dev_del(dev);
        rfcomm_dev_put(dev);
        return 0;
 }
@@ -667,7 +697,8 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
        BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
 
        if (--dev->opened == 0) {
-               device_move(dev->tty_dev, NULL);
+               if (dev->tty_dev->parent)
+                       device_move(dev->tty_dev, NULL);
 
                /* Close DLC and dettach TTY */
                rfcomm_dlc_close(dev->dlc, 0);