Commit 5177a838 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Johan Hedberg

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: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent f962fe32
...@@ -372,6 +372,8 @@ struct hci_dev { ...@@ -372,6 +372,8 @@ struct hci_dev {
atomic_t promisc; atomic_t promisc;
const char *hw_info;
const char *fw_info;
struct dentry *debugfs; struct dentry *debugfs;
struct device dev; struct device dev;
...@@ -1024,6 +1026,8 @@ int hci_resume_dev(struct hci_dev *hdev); ...@@ -1024,6 +1026,8 @@ int hci_resume_dev(struct hci_dev *hdev);
int hci_reset_dev(struct hci_dev *hdev); int hci_reset_dev(struct hci_dev *hdev);
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb);
void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...);
void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...);
int hci_dev_open(__u16 dev); int hci_dev_open(__u16 dev);
int hci_dev_close(__u16 dev); int hci_dev_close(__u16 dev);
int hci_dev_do_close(struct hci_dev *hdev); int hci_dev_do_close(struct hci_dev *hdev);
......
...@@ -3163,6 +3163,8 @@ void hci_unregister_dev(struct hci_dev *hdev) ...@@ -3163,6 +3163,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
device_del(&hdev->dev); device_del(&hdev->dev);
debugfs_remove_recursive(hdev->debugfs); debugfs_remove_recursive(hdev->debugfs);
kfree_const(hdev->hw_info);
kfree_const(hdev->fw_info);
destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->workqueue);
destroy_workqueue(hdev->req_workqueue); destroy_workqueue(hdev->req_workqueue);
...@@ -3266,6 +3268,28 @@ int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3266,6 +3268,28 @@ int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb)
} }
EXPORT_SYMBOL(hci_recv_diag); EXPORT_SYMBOL(hci_recv_diag);
void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
kfree_const(hdev->hw_info);
hdev->hw_info = kvasprintf_const(GFP_KERNEL, fmt, vargs);
va_end(vargs);
}
EXPORT_SYMBOL(hci_set_hw_info);
void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
kfree_const(hdev->fw_info);
hdev->fw_info = kvasprintf_const(GFP_KERNEL, fmt, vargs);
va_end(vargs);
}
EXPORT_SYMBOL(hci_set_fw_info);
/* ---- Interface to upper protocols ---- */ /* ---- Interface to upper protocols ---- */
int hci_register_cb(struct hci_cb *cb) int hci_register_cb(struct hci_cb *cb)
......
...@@ -76,6 +76,30 @@ static const struct file_operations __name ## _fops = { \ ...@@ -76,6 +76,30 @@ static const struct file_operations __name ## _fops = { \
.llseek = default_llseek, \ .llseek = default_llseek, \
} \ } \
#define DEFINE_INFO_ATTRIBUTE(__name, __field) \
static int __name ## _show(struct seq_file *f, void *ptr) \
{ \
struct hci_dev *hdev = f->private; \
\
hci_dev_lock(hdev); \
seq_printf(f, "%s\n", hdev->__field ? : ""); \
hci_dev_unlock(hdev); \
\
return 0; \
} \
\
static int __name ## _open(struct inode *inode, struct file *file) \
{ \
return single_open(file, __name ## _show, inode->i_private); \
} \
\
static const struct file_operations __name ## _fops = { \
.open = __name ## _open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
} \
static int features_show(struct seq_file *f, void *ptr) static int features_show(struct seq_file *f, void *ptr)
{ {
struct hci_dev *hdev = f->private; struct hci_dev *hdev = f->private;
...@@ -349,6 +373,9 @@ static const struct file_operations sc_only_mode_fops = { ...@@ -349,6 +373,9 @@ static const struct file_operations sc_only_mode_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
DEFINE_INFO_ATTRIBUTE(hardware_info, hw_info);
DEFINE_INFO_ATTRIBUTE(firmware_info, fw_info);
void hci_debugfs_create_common(struct hci_dev *hdev) void hci_debugfs_create_common(struct hci_dev *hdev)
{ {
debugfs_create_file("features", 0444, hdev->debugfs, hdev, debugfs_create_file("features", 0444, hdev->debugfs, hdev,
...@@ -382,6 +409,14 @@ void hci_debugfs_create_common(struct hci_dev *hdev) ...@@ -382,6 +409,14 @@ void hci_debugfs_create_common(struct hci_dev *hdev)
if (lmp_sc_capable(hdev) || lmp_le_capable(hdev)) if (lmp_sc_capable(hdev) || lmp_le_capable(hdev))
debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
hdev, &sc_only_mode_fops); hdev, &sc_only_mode_fops);
if (hdev->hw_info)
debugfs_create_file("hardware_info", 0444, hdev->debugfs,
hdev, &hardware_info_fops);
if (hdev->fw_info)
debugfs_create_file("firmware_info", 0444, hdev->debugfs,
hdev, &firmware_info_fops);
} }
static int inquiry_cache_show(struct seq_file *f, void *p) static int inquiry_cache_show(struct seq_file *f, void *p)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment