aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2013-10-19 10:09:12 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2013-10-19 11:56:56 -0400
commit4b4148e9acc1a51c454f133637e5dc7e298bd5bb (patch)
treefb9456ca985e3d86135abacdd6a5dc27efb47ada /net/bluetooth
parent4e70c7e71c5f9cf11013628ab5a0ced449b1c7b2 (diff)
Bluetooth: Add support for setting DUT mode
The Device Under Test (DUT) mode is useful for doing certification testing and so expose this as debugfs option. This mode is actually special since you can only enter it. Restoring normal operation means that a HCI Reset is required. The current mode value gets tracked as a new device flag and when disabling it, the correct command to reset the controller is sent. 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.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 8149e1303e2b..b5c8cb3c96d2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -58,6 +58,71 @@ static void hci_notify(struct hci_dev *hdev, int event)
58 58
59/* ---- HCI debugfs entries ---- */ 59/* ---- HCI debugfs entries ---- */
60 60
61static ssize_t dut_mode_read(struct file *file, char __user *user_buf,
62 size_t count, loff_t *ppos)
63{
64 struct hci_dev *hdev = file->private_data;
65 char buf[3];
66
67 buf[0] = test_bit(HCI_DUT_MODE, &hdev->dev_flags) ? 'Y': 'N';
68 buf[1] = '\n';
69 buf[2] = '\0';
70 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
71}
72
73static ssize_t dut_mode_write(struct file *file, const char __user *user_buf,
74 size_t count, loff_t *ppos)
75{
76 struct hci_dev *hdev = file->private_data;
77 struct sk_buff *skb;
78 char buf[32];
79 size_t buf_size = min(count, (sizeof(buf)-1));
80 bool enable;
81 int err;
82
83 if (!test_bit(HCI_UP, &hdev->flags))
84 return -ENETDOWN;
85
86 if (copy_from_user(buf, user_buf, buf_size))
87 return -EFAULT;
88
89 buf[buf_size] = '\0';
90 if (strtobool(buf, &enable))
91 return -EINVAL;
92
93 if (enable == test_bit(HCI_DUT_MODE, &hdev->dev_flags))
94 return -EALREADY;
95
96 hci_req_lock(hdev);
97 if (enable)
98 skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL,
99 HCI_CMD_TIMEOUT);
100 else
101 skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
102 HCI_CMD_TIMEOUT);
103 hci_req_unlock(hdev);
104
105 if (IS_ERR(skb))
106 return PTR_ERR(skb);
107
108 err = -bt_to_errno(skb->data[0]);
109 kfree_skb(skb);
110
111 if (err < 0)
112 return err;
113
114 change_bit(HCI_DUT_MODE, &hdev->dev_flags);
115
116 return count;
117}
118
119static const struct file_operations dut_mode_fops = {
120 .open = simple_open,
121 .read = dut_mode_read,
122 .write = dut_mode_write,
123 .llseek = default_llseek,
124};
125
61static int features_show(struct seq_file *f, void *ptr) 126static int features_show(struct seq_file *f, void *ptr)
62{ 127{
63 struct hci_dev *hdev = f->private; 128 struct hci_dev *hdev = f->private;
@@ -1256,6 +1321,14 @@ static int __hci_init(struct hci_dev *hdev)
1256 if (err < 0) 1321 if (err < 0)
1257 return err; 1322 return err;
1258 1323
1324 /* The Device Under Test (DUT) mode is special and available for
1325 * all controller types. So just create it early on.
1326 */
1327 if (test_bit(HCI_SETUP, &hdev->dev_flags)) {
1328 debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
1329 &dut_mode_fops);
1330 }
1331
1259 /* HCI_BREDR covers both single-mode LE, BR/EDR and dual-mode 1332 /* HCI_BREDR covers both single-mode LE, BR/EDR and dual-mode
1260 * BR/EDR/LE type controllers. AMP controllers only need the 1333 * BR/EDR/LE type controllers. AMP controllers only need the
1261 * first stage init. 1334 * first stage init.