From 51c6d71d1a689abfb51cdaf0cc10439f72d447da Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 22 Feb 2004 19:51:34 +0100 Subject: [PATCH] [Bluetooth] Initial sysfs and device class support 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 | 23 ++-- drivers/bluetooth/hci_usb.c | 1 + include/net/bluetooth/hci_core.h | 8 +- net/bluetooth/Makefile | 2 +- net/bluetooth/af_bluetooth.c | 16 ++- net/bluetooth/hci_core.c | 37 +----- net/bluetooth/hci_proc.c | 188 ------------------------------- net/bluetooth/hci_sysfs.c | 147 ++++++++++++++++++++++++ 8 files changed, 180 insertions(+), 242 deletions(-) delete mode 100644 net/bluetooth/hci_proc.c create mode 100644 net/bluetooth/hci_sysfs.c diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 0ff501d08a786..7becc5b351a7c 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -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); diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 14b8350652e48..c1f5178692fb1 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -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; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 03c51bba58a3a..3abfa75738646 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -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) diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 5c4d3ab348490..39cbf94a45744 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -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 diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 8aa8e3f74c482..910bb0bdf7e5c 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -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 #include @@ -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 "); +MODULE_AUTHOR("Maxim Krasnyansky , Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth Core ver " VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS_NETPROTO(PF_BLUETOOTH); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fd2a06d4a34cf..7be1b6724d3aa 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -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 index 494436344b1c3..0000000000000 --- a/net/bluetooth/hci_proc.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 index 0000000000000..3ef724ef48466 --- /dev/null +++ b/net/bluetooth/hci_sysfs.c @@ -0,0 +1,147 @@ +#include +#include +#include + +#include +#include + +#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); +} -- 2.53.0