aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2016-07-17 13:55:16 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2016-07-18 02:33:28 -0400
commit5177a83827cd0b8cf6ce0391b00dd4417352d2f1 (patch)
tree94051d92a967961a962188b74445fdb986faadd6 /net/bluetooth
parentf962fe32f2f85769cd835ddcecbff8c1d34cf561 (diff)
Bluetooth: Add debugfs fields for hardware and firmware info
Some Bluetooth controllers allow for reading hardware and firmware related vendor specific infos. If they are available, then they can be exposed via debugfs now. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_core.c24
-rw-r--r--net/bluetooth/hci_debugfs.c35
2 files changed, 59 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 98f6c3770736..ddf8432fe8fb 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3163,6 +3163,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
3163 device_del(&hdev->dev); 3163 device_del(&hdev->dev);
3164 3164
3165 debugfs_remove_recursive(hdev->debugfs); 3165 debugfs_remove_recursive(hdev->debugfs);
3166 kfree_const(hdev->hw_info);
3167 kfree_const(hdev->fw_info);
3166 3168
3167 destroy_workqueue(hdev->workqueue); 3169 destroy_workqueue(hdev->workqueue);
3168 destroy_workqueue(hdev->req_workqueue); 3170 destroy_workqueue(hdev->req_workqueue);
@@ -3266,6 +3268,28 @@ int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb)
3266} 3268}
3267EXPORT_SYMBOL(hci_recv_diag); 3269EXPORT_SYMBOL(hci_recv_diag);
3268 3270
3271void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...)
3272{
3273 va_list vargs;
3274
3275 va_start(vargs, fmt);
3276 kfree_const(hdev->hw_info);
3277 hdev->hw_info = kvasprintf_const(GFP_KERNEL, fmt, vargs);
3278 va_end(vargs);
3279}
3280EXPORT_SYMBOL(hci_set_hw_info);
3281
3282void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...)
3283{
3284 va_list vargs;
3285
3286 va_start(vargs, fmt);
3287 kfree_const(hdev->fw_info);
3288 hdev->fw_info = kvasprintf_const(GFP_KERNEL, fmt, vargs);
3289 va_end(vargs);
3290}
3291EXPORT_SYMBOL(hci_set_fw_info);
3292
3269/* ---- Interface to upper protocols ---- */ 3293/* ---- Interface to upper protocols ---- */
3270 3294
3271int hci_register_cb(struct hci_cb *cb) 3295int hci_register_cb(struct hci_cb *cb)
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
index 7db4220941cc..63df63ebfb24 100644
--- a/net/bluetooth/hci_debugfs.c
+++ b/net/bluetooth/hci_debugfs.c
@@ -76,6 +76,30 @@ static const struct file_operations __name ## _fops = { \
76 .llseek = default_llseek, \ 76 .llseek = default_llseek, \
77} \ 77} \
78 78
79#define DEFINE_INFO_ATTRIBUTE(__name, __field) \
80static int __name ## _show(struct seq_file *f, void *ptr) \
81{ \
82 struct hci_dev *hdev = f->private; \
83 \
84 hci_dev_lock(hdev); \
85 seq_printf(f, "%s\n", hdev->__field ? : ""); \
86 hci_dev_unlock(hdev); \
87 \
88 return 0; \
89} \
90 \
91static int __name ## _open(struct inode *inode, struct file *file) \
92{ \
93 return single_open(file, __name ## _show, inode->i_private); \
94} \
95 \
96static const struct file_operations __name ## _fops = { \
97 .open = __name ## _open, \
98 .read = seq_read, \
99 .llseek = seq_lseek, \
100 .release = single_release, \
101} \
102
79static int features_show(struct seq_file *f, void *ptr) 103static int features_show(struct seq_file *f, void *ptr)
80{ 104{
81 struct hci_dev *hdev = f->private; 105 struct hci_dev *hdev = f->private;
@@ -349,6 +373,9 @@ static const struct file_operations sc_only_mode_fops = {
349 .llseek = default_llseek, 373 .llseek = default_llseek,
350}; 374};
351 375
376DEFINE_INFO_ATTRIBUTE(hardware_info, hw_info);
377DEFINE_INFO_ATTRIBUTE(firmware_info, fw_info);
378
352void hci_debugfs_create_common(struct hci_dev *hdev) 379void hci_debugfs_create_common(struct hci_dev *hdev)
353{ 380{
354 debugfs_create_file("features", 0444, hdev->debugfs, hdev, 381 debugfs_create_file("features", 0444, hdev->debugfs, hdev,
@@ -382,6 +409,14 @@ void hci_debugfs_create_common(struct hci_dev *hdev)
382 if (lmp_sc_capable(hdev) || lmp_le_capable(hdev)) 409 if (lmp_sc_capable(hdev) || lmp_le_capable(hdev))
383 debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, 410 debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
384 hdev, &sc_only_mode_fops); 411 hdev, &sc_only_mode_fops);
412
413 if (hdev->hw_info)
414 debugfs_create_file("hardware_info", 0444, hdev->debugfs,
415 hdev, &hardware_info_fops);
416
417 if (hdev->fw_info)
418 debugfs_create_file("firmware_info", 0444, hdev->debugfs,
419 hdev, &firmware_info_fops);
385} 420}
386 421
387static int inquiry_cache_show(struct seq_file *f, void *p) 422static int inquiry_cache_show(struct seq_file *f, void *p)