]> git.hungrycats.org Git - linux/commitdiff
[Bluetooth] Initial sysfs and device class support
authorMarcel Holtmann <marcel@holtmann.org>
Sun, 22 Feb 2004 18:51:34 +0000 (19:51 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Sun, 22 Feb 2004 18:51:34 +0000 (19:51 +0100)
This patch adds the initial Bluetooth device class and sysfs support. This
new code replaces the hotplug and HCI proc interface.

drivers/bluetooth/bfusb.c
drivers/bluetooth/hci_usb.c
include/net/bluetooth/hci_core.h
net/bluetooth/Makefile
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_core.c
net/bluetooth/hci_proc.c [deleted file]
net/bluetooth/hci_sysfs.c [new file with mode: 0644]

index 0ff501d08a786533a03d98b552f3f9bd0b36bf41..7becc5b351a7c6af17896bdb7ee32aa26b349a2a 100644 (file)
@@ -639,23 +639,23 @@ error:
        return err;
 }
 
-static int bfusb_probe(struct usb_interface *iface, const struct usb_device_id *id)
+static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        const struct firmware *firmware;
-       struct usb_device *udev = interface_to_usbdev(iface);
+       struct usb_device *udev = interface_to_usbdev(intf);
        struct usb_host_endpoint *bulk_out_ep;
        struct usb_host_endpoint *bulk_in_ep;
        struct hci_dev *hdev;
        struct bfusb *bfusb;
 
-       BT_DBG("iface %p id %p", iface, id);
+       BT_DBG("intf %p id %p", intf, id);
 
        /* Check number of endpoints */
-       if (iface->altsetting[0].desc.bNumEndpoints < 2)
+       if (intf->altsetting[0].desc.bNumEndpoints < 2)
                return -EIO;
 
-       bulk_out_ep = &iface->altsetting[0].endpoint[0];
-       bulk_in_ep  = &iface->altsetting[0].endpoint[1];
+       bulk_out_ep = &intf->altsetting[0].endpoint[0];
+       bulk_in_ep  = &intf->altsetting[0].endpoint[1];
 
        if (!bulk_out_ep || !bulk_in_ep) {
                BT_ERR("Bulk endpoints not found");
@@ -702,6 +702,7 @@ static int bfusb_probe(struct usb_interface *iface, const struct usb_device_id *
 
        hdev->type = HCI_USB;
        hdev->driver_data = bfusb;
+       SET_HCIDEV_DEV(hdev, &intf->dev);
 
        hdev->open     = bfusb_open;
        hdev->close    = bfusb_close;
@@ -717,7 +718,7 @@ static int bfusb_probe(struct usb_interface *iface, const struct usb_device_id *
                goto error;
        }
 
-       usb_set_intfdata(iface, bfusb);
+       usb_set_intfdata(intf, bfusb);
 
        return 0;
 
@@ -731,17 +732,17 @@ done:
        return -EIO;
 }
 
-static void bfusb_disconnect(struct usb_interface *iface)
+static void bfusb_disconnect(struct usb_interface *intf)
 {
-       struct bfusb *bfusb = usb_get_intfdata(iface);
+       struct bfusb *bfusb = usb_get_intfdata(intf);
        struct hci_dev *hdev = &bfusb->hdev;
 
-       BT_DBG("iface %p", iface);
+       BT_DBG("intf %p", intf);
 
        if (!hdev)
                return;
 
-       usb_set_intfdata(iface, NULL);
+       usb_set_intfdata(intf, NULL);
 
        bfusb_close(hdev);
 
index 14b8350652e488684f87e1fa64cb9f1affdad034..c1f5178692fb1e34c90acdd3799ac747f6e22e81 100644 (file)
@@ -908,6 +908,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        hdev->type  = HCI_USB;
        hdev->driver_data = husb;
+       SET_HCIDEV_DEV(hdev, &intf->dev);
 
        hdev->open  = hci_usb_open;
        hdev->close = hci_usb_close;
index 03c51bba58a3a5e352bc0c160f4ab3e4036aad95..3abfa75738646fbedd526201e9f0b86740a6df19 100644 (file)
@@ -119,6 +119,8 @@ struct hci_dev {
        struct proc_dir_entry   *proc;
 #endif
 
+       struct class_device     class_dev;
+
        struct module           *owner;
 
        int (*open)(struct hci_dev *hdev);
@@ -385,8 +387,10 @@ static inline int hci_recv_frame(struct sk_buff *skb)
        return 0;
 }
 
-int  hci_dev_proc_init(struct hci_dev *hdev);
-void hci_dev_proc_cleanup(struct hci_dev *hdev);
+int hci_register_sysfs(struct hci_dev *hdev);
+void hci_unregister_sysfs(struct hci_dev *hdev);
+
+#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->class_dev.dev = (pdev))
 
 /* ----- LMP capabilities ----- */
 #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
index 5c4d3ab348490d4b54b74f6a0cb3beb68c3f32f5..39cbf94a45744828c5abed189e0dcd2b4e8a8da0 100644 (file)
@@ -9,4 +9,4 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm/
 obj-$(CONFIG_BT_BNEP)  += bnep/
 obj-$(CONFIG_BT_CMTP)  += cmtp/
 
-bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_proc.o lib.o syms.o
+bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o syms.o
index 8aa8e3f74c482b9d23cf44f850a7552444ad0147..910bb0bdf7e5c156493c93778da08e4dda484c21 100644 (file)
@@ -27,7 +27,7 @@
  *
  * $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $
  */
-#define VERSION "2.3"
+#define VERSION "2.4"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -331,8 +331,9 @@ struct net_proto_family bt_sock_family_ops = {
 
 extern int hci_sock_init(void);
 extern int hci_sock_cleanup(void);
-extern int hci_proc_init(void);
-extern int hci_proc_cleanup(void);
+
+extern int bt_sysfs_init(void);
+extern int bt_sysfs_cleanup(void);
 
 static int __init bt_init(void)
 {
@@ -356,15 +357,18 @@ static int __init bt_init(void)
 
        BT_INFO("HCI device and connection manager initialized");
 
-       hci_proc_init();
+       bt_sysfs_init();
+
        hci_sock_init();
+
        return 0;
 }
 
 static void __exit bt_cleanup(void)
 {
        hci_sock_cleanup();
-       hci_proc_cleanup();
+
+       bt_sysfs_cleanup();
 
        sock_unregister(PF_BLUETOOTH);
        kmem_cache_destroy(bt_sock_cache);
@@ -375,7 +379,7 @@ static void __exit bt_cleanup(void)
 subsys_initcall(bt_init);
 module_exit(bt_cleanup);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
index fd2a06d4a34cf2f31fdfa248bc5801d312162419..7be1b6724d3aad5eb6098cdc5c0b2deaaf2dfb50 100644 (file)
@@ -93,33 +93,6 @@ void hci_notify(struct hci_dev *hdev, int event)
        notifier_call_chain(&hci_notifier, event, hdev);
 }
 
-/* ---- HCI hotplug support ---- */
-
-#ifdef CONFIG_HOTPLUG
-
-static int hci_run_hotplug(char *dev, char *action)
-{
-       char *argv[3], *envp[5], dstr[20], astr[32];
-
-       sprintf(dstr, "DEVICE=%s", dev);
-       sprintf(astr, "ACTION=%s", action);
-
-        argv[0] = hotplug_path;
-        argv[1] = "bluetooth";
-        argv[2] = NULL;
-
-       envp[0] = "HOME=/";
-       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-       envp[2] = dstr;
-       envp[3] = astr;
-       envp[4] = NULL;
-       
-       return call_usermodehelper(argv[0], argv, envp, 0);
-}
-#else
-#define hci_run_hotplug(A...)
-#endif
-
 /* ---- HCI requests ---- */
 
 void hci_req_complete(struct hci_dev *hdev, int result)
@@ -841,10 +814,9 @@ int hci_register_dev(struct hci_dev *hdev)
                
        write_unlock_bh(&hci_dev_list_lock);
 
-       hci_dev_proc_init(hdev);
+       hci_register_sysfs(hdev);
 
        hci_notify(hdev, HCI_DEV_REG);
-       hci_run_hotplug(hdev->name, "register");
 
        return id;
 }
@@ -854,7 +826,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
 {
        BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
-       hci_dev_proc_cleanup(hdev);
+       hci_unregister_sysfs(hdev);
 
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
@@ -863,8 +835,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
        hci_dev_do_close(hdev);
 
        hci_notify(hdev, HCI_DEV_UNREG);
-       hci_run_hotplug(hdev->name, "unregister");
-       
+
        __hci_dev_put(hdev);
        return 0;
 }
@@ -873,7 +844,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
 int hci_suspend_dev(struct hci_dev *hdev)
 {
        hci_notify(hdev, HCI_DEV_SUSPEND);
-       hci_run_hotplug(hdev->name, "suspend");
        return 0;
 }
 
@@ -881,7 +851,6 @@ int hci_suspend_dev(struct hci_dev *hdev)
 int hci_resume_dev(struct hci_dev *hdev)
 {
        hci_notify(hdev, HCI_DEV_RESUME);
-       hci_run_hotplug(hdev->name, "resume");
        return 0;
 }       
 
diff --git a/net/bluetooth/hci_proc.c b/net/bluetooth/hci_proc.c
deleted file mode 100644 (file)
index 4944363..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * Bluetooth HCI Proc FS support.
- *
- * $Id: hci_proc.c,v 1.0 2002/04/17 17:37:16 maxk Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <net/sock.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#ifndef CONFIG_BT_HCI_CORE_DEBUG
-#undef  BT_DBG
-#define BT_DBG( A... )
-#endif
-
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_bt_hci;
-
-static int hci_seq_open(struct file *file, struct seq_operations *op, void *priv)
-{
-       struct seq_file *seq;
-
-       if (seq_open(file, op))
-               return -ENOMEM;
-
-       seq = file->private_data;
-       seq->private = priv;
-       return 0;
-}
-
-static void *inq_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       struct hci_dev *hdev = seq->private;
-       struct inquiry_entry *inq;
-       loff_t l = *pos;
-       
-       hci_dev_lock_bh(hdev);
-
-       for (inq = hdev->inq_cache.list; inq; inq = inq->next)
-               if (!l--)
-                       return inq;
-       return NULL;
-}
-
-static void *inq_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-       struct inquiry_entry *inq = e;
-       return inq->next;
-}
-
-static void inq_seq_stop(struct seq_file *seq, void *e)
-{
-       struct hci_dev *hdev = seq->private;
-       hci_dev_unlock_bh(hdev);
-}
-
-static int  inq_seq_show(struct seq_file *seq, void *e)
-{
-       struct inquiry_entry *inq = e;
-       struct inquiry_info  *info = &inq->info;
-
-       seq_printf(seq, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %u\n", batostr(&info->bdaddr), 
-                       info->pscan_rep_mode, info->pscan_period_mode, info->pscan_mode,
-                       info->dev_class[0], info->dev_class[1], info->dev_class[2],
-                       info->clock_offset, inq->timestamp);
-       return 0;
-}
-
-static struct seq_operations inq_seq_ops = {
-       .start  = inq_seq_start,
-       .next   = inq_seq_next,
-       .stop   = inq_seq_stop,
-       .show   = inq_seq_show 
-};
-
-static int inq_seq_open(struct inode *inode, struct file *file)
-{
-       return hci_seq_open(file, &inq_seq_ops, PDE(inode)->data);
-}
-
-static struct file_operations inq_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = inq_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-int hci_dev_proc_init(struct hci_dev *hdev)
-{
-       struct proc_dir_entry *e;
-       char id[10];
-
-       sprintf(id, "%d", hdev->id);
-
-       hdev->proc = proc_mkdir(id, proc_bt_hci);
-       if (!hdev->proc)
-               return -ENOMEM;
-
-       e = create_proc_entry("inquiry_cache", S_IRUGO, hdev->proc);
-       if (e) {
-               e->proc_fops = &inq_seq_fops;
-               e->data = (void *) hdev;
-       }
-
-        return 0;
-}
-
-void hci_dev_proc_cleanup(struct hci_dev *hdev)
-{
-       char id[10];
-       sprintf(id, "%d", hdev->id);
-
-       remove_proc_entry("inquiry_cache", hdev->proc);
-
-       remove_proc_entry(id, proc_bt_hci);
-}
-
-int  __init hci_proc_init(void)
-{
-       proc_bt_hci = proc_mkdir("hci", proc_bt);
-        return 0;
-}
-
-void __exit hci_proc_cleanup(void)
-{
-       remove_proc_entry("hci", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-int hci_dev_proc_init(struct hci_dev *hdev)
-{
-        return 0;
-}
-
-void hci_dev_proc_cleanup(struct hci_dev *hdev)
-{
-        return;
-}
-
-int  __init hci_proc_init(void)
-{
-        return 0;
-}
-
-void __exit hci_proc_cleanup(void)
-{
-        return;
-}
-
-#endif /* CONFIG_PROC_FS */
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
new file mode 100644 (file)
index 0000000..3ef724e
--- /dev/null
@@ -0,0 +1,147 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef CONFIG_BT_HCI_CORE_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#endif
+
+static ssize_t show_name(struct class_device *cdev, char *buf)
+{
+       struct hci_dev *hdev = class_get_devdata(cdev);
+       return sprintf(buf, "%s\n", hdev->name);
+}
+
+static ssize_t show_type(struct class_device *cdev, char *buf)
+{
+       struct hci_dev *hdev = class_get_devdata(cdev);
+       return sprintf(buf, "%d\n", hdev->type);
+}
+
+static ssize_t show_address(struct class_device *cdev, char *buf)
+{
+       struct hci_dev *hdev = class_get_devdata(cdev);
+       bdaddr_t bdaddr;
+       baswap(&bdaddr, &hdev->bdaddr);
+       return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_flags(struct class_device *cdev, char *buf)
+{
+       struct hci_dev *hdev = class_get_devdata(cdev);
+       return sprintf(buf, "0x%lx\n", hdev->flags);
+}
+
+static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf)
+{
+       struct hci_dev *hdev = class_get_devdata(cdev);
+       struct inquiry_cache *cache = &hdev->inq_cache;
+       struct inquiry_entry *e;
+       int n = 0;
+
+       hci_dev_lock_bh(hdev);
+
+       for (e = cache->list; e; e = e->next) {
+               struct inquiry_info *info = &e->info;
+               bdaddr_t bdaddr;
+               baswap(&bdaddr, &info->bdaddr);
+               n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x 0x%.2x %u\n",
+                               batostr(&bdaddr),
+                               info->pscan_rep_mode, info->pscan_period_mode, info->pscan_mode,
+                               info->dev_class[0], info->dev_class[1], info->dev_class[2],
+                               info->clock_offset, 0, e->timestamp);
+       }
+
+       hci_dev_unlock_bh(hdev);
+       return n;
+}
+
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
+
+static struct class_device_attribute *bt_attrs[] = {
+       &class_device_attr_name,
+       &class_device_attr_type,
+       &class_device_attr_address,
+       &class_device_attr_flags,
+       &class_device_attr_inquiry_cache,
+       NULL
+};
+
+#ifdef CONFIG_HOTPLUG
+static int bt_hotplug(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
+{
+       struct hci_dev *hdev = class_get_devdata(cdev);
+       int n, i = 0;
+
+       envp[i++] = buf;
+       n = snprintf(buf, size, "INTERFACE=%s", hdev->name) + 1;
+       buf += n;
+       size -= n;
+
+       if ((size <= 0) || (i >= num_envp))
+               return -ENOMEM;
+
+       envp[i] = 0;
+       return 0;
+}
+#endif
+
+static void bt_release(struct class_device *cdev)
+{
+}
+
+static struct class bt_class = {
+       .name           = "bluetooth",
+       .release        = bt_release,
+#ifdef CONFIG_HOTPLUG
+       .hotplug        = bt_hotplug,
+#endif
+};
+
+int hci_register_sysfs(struct hci_dev *hdev)
+{
+       struct class_device *cdev = &hdev->class_dev;
+       int i, err;
+
+       BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+
+       cdev->class = &bt_class;
+       class_set_devdata(cdev, hdev);
+
+       strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE);
+       err = class_device_register(cdev);
+       if (err < 0)
+               return err;
+
+       for (i = 0; bt_attrs[i]; i++)
+               class_device_create_file(cdev, bt_attrs[i]);
+
+       return 0;
+}
+
+void hci_unregister_sysfs(struct hci_dev *hdev)
+{
+       struct class_device * cdev = &hdev->class_dev;
+
+       BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+
+       class_device_del(cdev);
+}
+
+int __init bt_sysfs_init(void)
+{
+       return class_register(&bt_class);
+}
+
+void __exit bt_sysfs_cleanup(void)
+{
+       class_unregister(&bt_class);
+}